diff --git a/.gitignore b/.gitignore index b4d6295e..ebbad358 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ pkg/ *.gem .bundle/ .yardoc/ +.vscode/ Gemfile.lock /_yardoc/ *.DS_store diff --git a/README.md b/README.md index 117ca2f9..e5b5e8f5 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ A Ruby script that colorizes the `ls` output with color and icons. Here are the - `--gs` (or) `--git-status` - `--sd` (or) `--sort-dirs` or `--group-directories-first` - `--sf` (or) `--sort-files` + - `--df` (or) `--dots-first` - `-t` - [Combination of flags](#combination-of-flags) - [Installation](#installation) diff --git a/colorls.gemspec b/colorls.gemspec index 0a7b5e46..9d6069b2 100644 --- a/colorls.gemspec +++ b/colorls.gemspec @@ -12,6 +12,8 @@ POST_INSTALL_MESSAGE = %( Sort by files : -sf flag has been renamed to --sf Git status : -gs flag has been renamed to --gs + Sort Dots First: --df, --dots-first - sort dot-files and dot-folders first + Clubbed flags : `colorls -ald` works Help menu : `colorls -h` provides all possible flag options diff --git a/lib/colorls/core.rb b/lib/colorls/core.rb index 89a647f6..e8cd4083 100644 --- a/lib/colorls/core.rb +++ b/lib/colorls/core.rb @@ -196,22 +196,38 @@ def filter_contents def sort_contents case @sort when :extension - @contents.sort_by! do |f| - name = f.name - ext = File.extname(name) - name = name.chomp(ext) unless ext.empty? - [ext, name].map { |s| CLocale.strxfrm(s) } - end + sort_by_extension when :time @contents.sort_by! { |a| -a.mtime.to_f } when :size @contents.sort_by! { |a| -a.size } + when :df + sort_by_dot_first else @contents.sort_by! { |a| CLocale.strxfrm(a.name) } end @contents.reverse! if @reverse end + def sort_by_extension + @contents.sort_by! do |f| + name = f.name + ext = File.extname(name) + name = name.chomp(ext) unless ext.empty? + [ext, name].map { |s| CLocale.strxfrm(s) } + end + end + + def sort_by_dot_first + @contents.sort_by! do |a| + name = a.name + # Check if the name starts with a dot + dot_prefix = name.start_with?('.') ? 0 : 1 + # Return an array where dot-prefixed names are sorted first + [dot_prefix, CLocale.strxfrm(name)] + end + end + def group_contents return unless @group @@ -415,22 +431,40 @@ def file_color(file, key) def options(content) if content.directory? - key = content.name.downcase.to_sym - key = @folder_aliases[key] unless @folders.key? key - key = :folder if key.nil? - color = @colors[:dir] - group = :folders + dir_options(content) else - key = File.extname(content.name).delete_prefix('.').downcase.to_sym - key = @file_aliases[key] unless @files.key? key - color = file_color(content, key) - group = @files.key?(key) ? :recognized_files : :unrecognized_files - key = :file if key.nil? + file_options(content) end + end + + def dir_options(content) + key = content.name.downcase.to_sym + key = @folder_aliases[key] unless @folders.key? key + key = :folder if key.nil? + color = @colors[:dir] + group = :folders + [key, color, group] + end + def file_options(content) + key = determine_key_for_file(content) + key = @file_aliases[key] unless @files.key? key + color = file_color(content, key) + group = @files.key?(key) ? :recognized_files : :unrecognized_files + key = :file if key.nil? [key, color, group] end + def determine_key_for_file(content) + extension = File.extname(content.name).delete_prefix('.').downcase + if extension.empty? + filename = content.name.match(/\A\.?(.+)/)[1] + filename.downcase.to_sym + else + extension.to_sym + end || :default + end + def tree_contents(path) @contents = Dir.entries(path, encoding: ColorLS.file_encoding) diff --git a/lib/colorls/flags.rb b/lib/colorls/flags.rb index 92379ac2..e7857d1b 100644 --- a/lib/colorls/flags.rb +++ b/lib/colorls/flags.rb @@ -116,23 +116,24 @@ def add_sort_options(options) options.separator '' options.separator 'sorting options:' options.separator '' + configure_sort_options(options) + end + + def configure_sort_options(options) options.on('--sd', '--sort-dirs', '--group-directories-first', 'sort directories first') { @opts[:group] = :dirs } options.on('--sf', '--sort-files', 'sort files first') { @opts[:group] = :files } + options.on('--df', '--dots-first', 'sort dot-files and dot-folders first') { @opts[:sort] = :df } options.on('-t', 'sort by modification time, newest first') { @opts[:sort] = :time } options.on('-U', 'do not sort; list entries in directory order') { @opts[:sort] = false } options.on('-S', 'sort by file size, largest first') { @opts[:sort] = :size } options.on('-X', 'sort by file extension') { @opts[:sort] = :extension } options.on( '--sort=WORD', - %w[none time size extension], - 'sort by WORD instead of name: none, size (-S), time (-t), extension (-X)' + %w[none time size extension df], + 'sort by WORD instead of name: none, size (-S), time (-t), extension (-X), df (--df)' ) do |word| - @opts[:sort] = case word - when 'none' then false - else word.to_sym - end + @opts[:sort] = (word == 'none' ? false : word.to_sym) end - options.on('-r', '--reverse', 'reverse order while sorting') { @opts[:reverse] = true } end diff --git a/lib/yaml/file_aliases.yaml b/lib/yaml/file_aliases.yaml index 39334748..2621d89f 100644 --- a/lib/yaml/file_aliases.yaml +++ b/lib/yaml/file_aliases.yaml @@ -8,7 +8,11 @@ mp3: audio ogg: audio opus: audio wav: audio +h: c editorconfig: conf +chh: cpp +cxx: cpp +hpp: cpp scss: css docx: doc gdoc: doc @@ -20,9 +24,14 @@ otf: font ttf: font woff: font woff2: font +gitattributes: git gitconfig: git gitignore: git gitignore_global: git +gitkeep: git +gitmodules: git +gitreflog: git +wget-hsts: history lhs: hs avif: image bmp: image @@ -41,6 +50,10 @@ webp: image jar: java properties: json tsx: jsx +lesshst: less +depend: makefile +make: makefile +mk: makefile license: md markdown: md mkd: md @@ -50,13 +63,20 @@ gslides: ppt odp: ppt pptx: ppt ipynb: py +pxd: py pyc: py +pyd: py +pyi: py +pyo: py +pyx: py rdata: r rds: r +rhistory: r gemfile: rb gemspec: rb guardfile: rb lock: rb +mkshrc: rb procfile: rb rakefile: rb rspec: rb @@ -66,13 +86,31 @@ ru: rb erb: rubydoc slim: rubydoc bash: shell +bash_aliases: shell +bash_completion: shell +bash_env: shell +bash_functions: shell bash_history: shell +bash_logout: shell bash_profile: shell bashrc: shell +environment: shell fish: shell +inputrc: shell +oh-my-zsh: shell +osh-update: shell +pre-oh-my-zsh: shell +profile: shell sh: shell +zlogin: shell +zlogout: shell +zprofile: shell zsh: shell +zsh-syntax-highlighting: shell zsh-theme: shell +zsh-update: shell +zsh_history: shell +zshenv: shell zshrc: shell stylus: styl cls: tex @@ -83,6 +121,14 @@ mov: video mp4: video ogv: video webm: video +exrc: vim +gvimrc: vim +vim-update: vim +vimbackup: vim +viminfo: vim +vimrc: vim +vimswap: vim +vimtags: vim bat: windows exe: windows ini: windows @@ -93,6 +139,8 @@ xlsx: xls xul: xml yaml: yml 7z: zip +bz: zip +bz2: zip gz: zip rar: zip tar: zip diff --git a/lib/yaml/files.yaml b/lib/yaml/files.yaml index 2f77db43..0a7515f2 100644 --- a/lib/yaml/files.yaml +++ b/lib/yaml/files.yaml @@ -25,6 +25,7 @@ gform: "" git: "" go: "" gruntfile.js: "" +history: "" hs: "" html: "" image: "" @@ -36,6 +37,7 @@ jsx: "" less: "" log: "" lua: "" +makefile: "" md: "" mustache: "" npmignore: "" @@ -62,7 +64,7 @@ ts: "" twig: "" txt: "" video: "" -vim: "" +vim: "" vue: "﵂" windows: "" xls: "" diff --git a/lib/yaml/folders.yaml b/lib/yaml/folders.yaml index b43b7af9..aec31c00 100644 --- a/lib/yaml/folders.yaml +++ b/lib/yaml/folders.yaml @@ -1,11 +1,46 @@ .atom: "" +.cache: "" +.config: "" +.dotnet: "󰪮" .git: "" .github: "" +.local: "" +.mono: "󰪮" +.pyenv: "" +.rbenv: "" +.repo: "" +.ruby-lsp: "" +.rustup: "" .rvm: "" +.ssh: "󰣀" +.tmux: "" .Trash: "" +.venv: "" +.vim: "" .vscode: "" +.vscode-insiders: "" +.vscode-r: "" +.vscode-remote-containers: "" +.vscode-server: "" +.vscode-server-insiders: "" +__pycache__: "" config: "" +coverage: "" +dist-packages: "" +eggs: "" +exe: "" folder: "" +go: "" hidden: "" lib: "" +man: "󰗚" node_modules: "" +pkg: "" +site-packages: "" +spec: "󰙨" +src: "󰳐" +test: "󰙨" +tests: "󰙨" +venv: "" +wheels: "" + diff --git a/man/colorls.1 b/man/colorls.1 new file mode 100644 index 00000000..dd89c983 --- /dev/null +++ b/man/colorls.1 @@ -0,0 +1,211 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "COLORLS" "1" "April 2024" "colorls 1.5.0" "colorls Manual" +. +.SH "NAME" +\fBcolorls\fR \- list directory contents with colors and icons +. +.SH "SYNOPSIS" +\fBcolorls\fR [OPTION]\.\.\. [FILE]\.\.\. +. +.br +. +.SH "DESCRIPTION" +List information about the given FILEs\. Uses different colors and icons for known file types\. +. +.P +By default, the output is sorted alphabetically\. +. +.P +Mandatory arguments to long options are mandatory for short options too\. +. +.SH "OPTIONS" +. +.TP +\fB\-a\fR, \fB\-\-all\fR +do not ignore entries starting with \. +. +.TP +\fB\-A\fR, \fB\-\-almost\-all\fR +do not list \. and \.\. +. +.TP +\fB\-d\fR, \fB\-\-dirs\fR +show only directories +. +.TP +\fB\-f\fR, \fB\-\-files\fR +show only files +. +.TP +\fB\-\-gs\fR, \fB\-\-git\-status\fR +show git status for each file +. +.TP +\fB\-p\fR +append / indicator to directories +. +.TP +\fB\-i\fR, \fB\-\-inode\fR +show inode number +. +.TP +\fB\-\-report\fR +show report: short, long (default if omitted) +. +.TP +\fB\-\-indicator\-style\fR +append indicator with style STYLE to entry names: none, slash (\-p) (default) +. +.TP +\fB\-\-format\fR +use format: across (\-x), horizontal (\-x), long (\-l), single\-column (\-1), vertical (\-C) +. +.TP +\fB\-1\fR +list one file per line +. +.TP +\fB\-\-tree\fR +shows tree view of the directory +. +.TP +\fB\-x\fR +list entries by lines instead of by columns +. +.TP +\fB\-C\fR +list entries by columns instead of by lines +. +.TP +\fB\-\-without\-icons\fR +list entries without icons +. +.TP +\fB\-l\fR, \fB\-\-long\fR +use a long listing format +. +.TP +\fB\-o\fR +use a long listing format without group information +. +.TP +\fB\-g\fR +use a long listing format without owner information +. +.TP +\fB\-G\fR, \fB\-\-no\-group\fR +show no group information in a long listing +. +.TP +\fB\-\-time\-style\fR +use time display format +. +.TP +\fB\-\-no\-hardlinks\fR +show no hard links count in a long listing +. +.TP +\fB\-L\fR +show information on the destination of symbolic links +. +.TP +\fB\-\-non\-human\-readable\fR +show file sizes in bytes only +. +.TP +\fB\-\-sd\fR, \fB\-\-sort\-dirs\fR, \fB\-\-group\-directories\-first\fR +sort directories first +. +.TP +\fB\-\-sf\fR, \fB\-\-sort\-files\fR +sort files first +. +.TP +\fB\-\-df\fR, \fB\-\-dots\-first\fR +sort dot\-files and dot\-folders first +. +.TP +\fB\-t\fR +sort by modification time, newest first +. +.TP +\fB\-U\fR +do not sort; list entries in directory order +. +.TP +\fB\-S\fR +sort by file size, largest first +. +.TP +\fB\-X\fR +sort by file extension +. +.TP +\fB\-\-sort\fR +sort by WORD instead of name: none, size (\-S), time (\-t), extension (\-X), df (\-\-df) +. +.TP +\fB\-r\fR, \fB\-\-reverse\fR +reverse order while sorting +. +.TP +\fB\-h\fR, \fB\-\-human\-readable\fR: + +. +.TP +\fB\-\-color\fR +colorize the output: auto, always (default if omitted), never +. +.TP +\fB\-\-light\fR +use light color scheme +. +.TP +\fB\-\-dark\fR +use dark color scheme +. +.TP +\fB\-\-hyperlink\fR: + +. +.TP +\fB\-\-help\fR +prints this help +. +.TP +\fB\-\-version\fR +show version +. +.SH "EXAMPLES" +. +.TP +show the given file: +. +.IP +\fBcolorls README\.md\fR +. +.TP +show matching files and list matching directories: +. +.IP +\fBcolorls *\fR +. +.TP +filter output by a regular expression: +. +.IP +\fBcolorls | grep PATTERN\fR +. +.TP +several short options can be combined: +. +.IP +\fBcolorls \-d \-l \-a\fR +. +.br +\fBcolorls \-dla\fR +. +.SH "AUTHOR" +Written by Athitya Kumar\. diff --git a/spec/color_ls/flags_spec.rb b/spec/color_ls/flags_spec.rb index d09b1f61..69188582 100644 --- a/spec/color_ls/flags_spec.rb +++ b/spec/color_ls/flags_spec.rb @@ -195,6 +195,16 @@ end end + context 'with --sort=df flag' do + let(:args) { ['--sort=df', '--group-directories-first', '-1', FIXTURES] } + + it 'sort dot-files and dot-folders first' do + allow($stdout).to receive(:tty?).and_return(true) + + expect { subject }.to output(/symlinks.+a-file.+z-file/m).to_stdout + end + end + context 'with --help flag' do let(:args) { ['--help', FIXTURES] } diff --git a/test/checks b/test/checks index 9df9f6cd..e4471de0 100644 --- a/test/checks +++ b/test/checks @@ -15,6 +15,9 @@ OK colorls -r OK colorls --sd OK colorls --sf +OK colorls -laA --df +OK colorls -laA --dots-first +OK colorls -laA --sort=df OK colorls --hyperlink OK colorls -t OK colorls --sort=time diff --git a/zsh/_colorls b/zsh/_colorls new file mode 100644 index 00000000..1e5b1a10 --- /dev/null +++ b/zsh/_colorls @@ -0,0 +1,60 @@ +#compdef colorls + +typeset -A opt_args +local context state line + +_arguments -s -S \ + "-a[do not ignore entries starting with .]" \ + "--all[do not ignore entries starting with .]" \ + "-A[do not list . and ..]" \ + "--almost-all[do not list . and ..]" \ + "-d[show only directories]" \ + "--dirs[show only directories]" \ + "-f[show only files]" \ + "--files[show only files]" \ + "--gs[show git status for each file]" \ + "--git-status[show git status for each file]" \ + "-p[append / indicator to directories]" \ + "-i[show inode number]" \ + "--inode[show inode number]" \ + "--report[show report: short, long (default if omitted)]" \ + "--indicator-style[append indicator with style STYLE to entry names: none, slash (-p) (default)]" \ + "--format[use format: across (-x), horizontal (-x), long (-l), single-column (-1), vertical (-C)]" \ + "-1[list one file per line]" \ + "--tree[shows tree view of the directory]" \ + "-x[list entries by lines instead of by columns]" \ + "-C[list entries by columns instead of by lines]" \ + "--without-icons[list entries without icons]" \ + "-l[use a long listing format]" \ + "--long[use a long listing format]" \ + "-o[use a long listing format without group information]" \ + "-g[use a long listing format without owner information]" \ + "-G[show no group information in a long listing]" \ + "--no-group[show no group information in a long listing]" \ + "--time-style[use time display format]" \ + "--no-hardlinks[show no hard links count in a long listing]" \ + "-L[show information on the destination of symbolic links]" \ + "--non-human-readable[show file sizes in bytes only]" \ + "--sd[sort directories first]" \ + "--sort-dirs[sort directories first]" \ + "--group-directories-first[sort directories first]" \ + "--sf[sort files first]" \ + "--sort-files[sort files first]" \ + "--df[sort dot-files and dot-folders first]" \ + "--dots-first[sort dot-files and dot-folders first]" \ + "-t[sort by modification time, newest first]" \ + "-U[do not sort; list entries in directory order]" \ + "-S[sort by file size, largest first]" \ + "-X[sort by file extension]" \ + "--sort[sort by WORD instead of name: none, size (-S), time (-t), extension (-X), df (--df)]" \ + "-r[reverse order while sorting]" \ + "--reverse[reverse order while sorting]" \ + "-h[]" \ + "--human-readable[]" \ + "--color[colorize the output: auto, always (default if omitted), never]" \ + "--light[use light color scheme]" \ + "--dark[use dark color scheme]" \ + "--hyperlink[]" \ + "--help[prints this help]" \ + "--version[show version]" \ + '*:file:_files' && return 0