Finish copying the GNU ls coloring algorithm
This commit is contained in:
		
							parent
							
								
									1ba2709fda
								
							
						
					
					
						commit
						6e34f480a9
					
				
							
								
								
									
										58
									
								
								sdn.cpp
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								sdn.cpp
									
									
									
									
									
								
							| @ -318,6 +318,7 @@ static struct { | |||||||
| 
 | 
 | ||||||
| 	map<int, chtype> ls_colors;         ///< LS_COLORS decoded
 | 	map<int, chtype> ls_colors;         ///< LS_COLORS decoded
 | ||||||
| 	map<string, chtype> ls_exts;        ///< LS_COLORS file extensions
 | 	map<string, chtype> ls_exts;        ///< LS_COLORS file extensions
 | ||||||
|  | 	bool ls_symlink_as_target;          ///< ln=target in dircolors
 | ||||||
| 
 | 
 | ||||||
| 	// Refreshed by reload():
 | 	// Refreshed by reload():
 | ||||||
| 
 | 
 | ||||||
| @ -326,17 +327,34 @@ static struct { | |||||||
| 	struct tm now;                      ///< Current local time for display
 | 	struct tm now;                      ///< Current local time for display
 | ||||||
| } g; | } g; | ||||||
| 
 | 
 | ||||||
| fun ls_format (const string &filename, const struct stat &info) -> chtype { | // The coloring logic has been more or less exactly copied from GNU ls,
 | ||||||
|  | // simplified and rewritten to reflect local implementation specifics
 | ||||||
|  | fun ls_is_colored (int type) -> bool { | ||||||
|  | 	auto i = g.ls_colors.find (type); | ||||||
|  | 	return i != g.ls_colors.end () && i->second != 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fun ls_format (const entry &e, bool for_target) -> chtype { | ||||||
| 	int type = LS_ORPHAN; | 	int type = LS_ORPHAN; | ||||||
| 	auto set = [&](int t) { if (g.ls_colors.count (t)) type = t; }; | 	auto set = [&](int t) { if (ls_is_colored (t)) type = t; }; | ||||||
| 	// TODO: LS_MISSING if available and this is a missing symlink target
 | 
 | ||||||
| 	if (S_ISREG (info.st_mode)) { | 	const auto &name = for_target | ||||||
|  | 		? e.target_path : e.filename; | ||||||
|  | 	const auto &info = | ||||||
|  | 		(for_target || (g.ls_symlink_as_target && e.target_info.st_mode)) | ||||||
|  | 		? e.target_info : e.info; | ||||||
|  | 
 | ||||||
|  | 	if (for_target && info.st_mode == 0) { | ||||||
|  | 		// This differs from GNU ls: we use ORPHAN when MISSING is not set,
 | ||||||
|  | 		// but GNU ls colors by dirent::d_type
 | ||||||
|  | 		set (LS_MISSING); | ||||||
|  | 	} else if (S_ISREG (info.st_mode)) { | ||||||
| 		type = LS_FILE; | 		type = LS_FILE; | ||||||
| 		if (info.st_nlink > 1) | 		if (info.st_nlink > 1) | ||||||
| 			set (LS_MULTIHARDLINK); | 			set (LS_MULTIHARDLINK); | ||||||
| 		if ((info.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) | 		if ((info.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) | ||||||
| 			set (LS_EXECUTABLE); | 			set (LS_EXECUTABLE); | ||||||
| 		if (lgetxattr (filename.c_str (), "security.capability", NULL, 0) >= 0) | 		if (lgetxattr (name.c_str (), "security.capability", NULL, 0) >= 0) | ||||||
| 			set (LS_CAPABILITY); | 			set (LS_CAPABILITY); | ||||||
| 		if ((info.st_mode & S_ISGID)) | 		if ((info.st_mode & S_ISGID)) | ||||||
| 			set (LS_SETGID); | 			set (LS_SETGID); | ||||||
| @ -351,10 +369,10 @@ fun ls_format (const string &filename, const struct stat &info) -> chtype { | |||||||
| 		if ((info.st_mode & S_ISVTX) && (info.st_mode & S_IWOTH)) | 		if ((info.st_mode & S_ISVTX) && (info.st_mode & S_IWOTH)) | ||||||
| 			set (LS_STICKY_OTHER_WRITABLE); | 			set (LS_STICKY_OTHER_WRITABLE); | ||||||
| 	} else if (S_ISLNK (info.st_mode)) { | 	} else if (S_ISLNK (info.st_mode)) { | ||||||
| 		// TODO: LS_ORPHAN when symlink target is missing and either
 |  | ||||||
| 		//   a/ "li" is "target", or
 |  | ||||||
| 		//   b/ LS_ORPHAN is available
 |  | ||||||
| 		type = LS_SYMLINK; | 		type = LS_SYMLINK; | ||||||
|  | 		if (!e.target_info.st_mode | ||||||
|  | 		 && (ls_is_colored (LS_ORPHAN) || g.ls_symlink_as_target)) | ||||||
|  | 			type = LS_ORPHAN; | ||||||
| 	} else if (S_ISFIFO (info.st_mode)) { | 	} else if (S_ISFIFO (info.st_mode)) { | ||||||
| 		type = LS_FIFO; | 		type = LS_FIFO; | ||||||
| 	} else if (S_ISSOCK (info.st_mode)) { | 	} else if (S_ISSOCK (info.st_mode)) { | ||||||
| @ -370,9 +388,9 @@ fun ls_format (const string &filename, const struct stat &info) -> chtype { | |||||||
| 	if (x != g.ls_colors.end ()) | 	if (x != g.ls_colors.end ()) | ||||||
| 		format = x->second; | 		format = x->second; | ||||||
| 
 | 
 | ||||||
| 	auto dot = filename.find_last_of ('.'); | 	auto dot = name.find_last_of ('.'); | ||||||
| 	if (dot != string::npos && type == LS_FILE) { | 	if (dot != string::npos && type == LS_FILE) { | ||||||
| 		const auto x = g.ls_exts.find (filename.substr (++dot)); | 		const auto x = g.ls_exts.find (name.substr (++dot)); | ||||||
| 		if (x != g.ls_exts.end ()) | 		if (x != g.ls_exts.end ()) | ||||||
| 			format = x->second; | 			format = x->second; | ||||||
| 	} | 	} | ||||||
| @ -395,8 +413,8 @@ fun make_entry (const struct dirent *f) -> entry { | |||||||
| 		e.cols[entry::USER] = e.cols[entry::GROUP] = | 		e.cols[entry::USER] = e.cols[entry::GROUP] = | ||||||
| 		e.cols[entry::SIZE] = e.cols[entry::MTIME] = apply_attrs (L"?", 0); | 		e.cols[entry::SIZE] = e.cols[entry::MTIME] = apply_attrs (L"?", 0); | ||||||
| 
 | 
 | ||||||
| 		auto format = ls_format (e.filename, info); | 		e.cols[entry::FILENAME] = | ||||||
| 		e.cols[entry::FILENAME] = apply_attrs (to_wide (e.filename), format); | 			apply_attrs (to_wide (e.filename), ls_format (e, false)); | ||||||
| 		return e; | 		return e; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -407,7 +425,8 @@ fun make_entry (const struct dirent *f) -> entry { | |||||||
| 			e.target_path = "?"; | 			e.target_path = "?"; | ||||||
| 		} else { | 		} else { | ||||||
| 			e.target_path = buf; | 			e.target_path = buf; | ||||||
| 			(void) lstat (buf, &e.target_info); | 			// If a symlink links to another symlink, we follow all the way
 | ||||||
|  | 			(void) stat (buf, &e.target_info); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -441,11 +460,10 @@ fun make_entry (const struct dirent *f) -> entry { | |||||||
| 	e.cols[entry::MTIME] = apply_attrs (to_wide (buf), 0); | 	e.cols[entry::MTIME] = apply_attrs (to_wide (buf), 0); | ||||||
| 
 | 
 | ||||||
| 	auto &fn = e.cols[entry::FILENAME] = | 	auto &fn = e.cols[entry::FILENAME] = | ||||||
| 		apply_attrs (to_wide (e.filename), ls_format (e.filename, info)); | 		apply_attrs (to_wide (e.filename), ls_format (e, false)); | ||||||
| 	if (!e.target_path.empty ()) { | 	if (!e.target_path.empty ()) { | ||||||
| 		fn.append (apply_attrs (to_wide (" -> "), 0)); | 		fn.append (apply_attrs (to_wide (" -> "), 0)); | ||||||
| 		fn.append (apply_attrs (to_wide (e.target_path), | 		fn.append (apply_attrs (to_wide (e.target_path), ls_format (e, true))); | ||||||
| 			ls_format (e.target_path, e.target_info))); |  | ||||||
| 	} | 	} | ||||||
| 	return e; | 	return e; | ||||||
| } | } | ||||||
| @ -767,11 +785,11 @@ fun load_ls_colors (vector<string> colors) { | |||||||
| 		auto equal = pair.find ('='); | 		auto equal = pair.find ('='); | ||||||
| 		if (equal == string::npos) | 		if (equal == string::npos) | ||||||
| 			continue; | 			continue; | ||||||
| 		attrs[pair.substr (0, equal)] = | 		auto key = pair.substr (0, equal), value = pair.substr (equal + 1); | ||||||
| 			decode_ansi_sgr (split (pair.substr (equal + 1), ";")); | 		if (key != g_ls_colors[LS_SYMLINK] | ||||||
|  | 		 || !(g.ls_symlink_as_target = value == "target")) | ||||||
|  | 			attrs[key] = decode_ansi_sgr (split (value, ";")); | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	// `LINK target` i.e. `ln=target` is not supported now
 |  | ||||||
| 	for (int i = 0; i < LS_COUNT; i++) { | 	for (int i = 0; i < LS_COUNT; i++) { | ||||||
| 		auto m = attrs.find (g_ls_colors[i]); | 		auto m = attrs.find (g_ls_colors[i]); | ||||||
| 		if (m != attrs.end ()) | 		if (m != attrs.end ()) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user