Skip to content

Commit

Permalink
add mime type option
Browse files Browse the repository at this point in the history
  • Loading branch information
mike-ward committed Jan 3, 2025
1 parent fca8455 commit 5c04bca
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 37 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
- almost all option (-A)
- full path option (-F)
- add relative time option (-T)
= add mime type (-M)

## [2024.6]
### Added
Expand Down
18 changes: 18 additions & 0 deletions lsv/entry.v
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import crypto.sha1
import crypto.sha256
import crypto.sha512
import crypto.blake2b
import net.http.mime
import math

struct Entry {
Expand All @@ -26,6 +27,7 @@ struct Entry {
size_ki string
size_kb string
checksum string
mime_type string
invalid bool // lstat could not access
}

Expand Down Expand Up @@ -79,6 +81,9 @@ fn make_entry(file string, dir_name string, options Options) Entry {
is_exe := !is_dir && is_executable(stat)
is_file := filetype == .regular
indicator := if is_dir && options.dir_indicator { '/' } else { '' }
if options.mime_type {
os.file_ext(file).trim_left('.')
}
name := if options.full_path { os.real_path(path) + indicator } else { file + indicator }

return Entry{
Expand All @@ -101,6 +106,7 @@ fn make_entry(file string, dir_name string, options Options) Entry {
size_ki: if options.size_ki { readable_size(size, true) } else { '' }
size_kb: if options.size_kb { readable_size(size, false) } else { '' }
checksum: if is_file { checksum(file, dir_name, options) } else { '' }
mime_type: get_mime_type(file, filetype, is_exe)
invalid: invalid
}
}
Expand Down Expand Up @@ -155,6 +161,18 @@ fn checksum(name string, dir_name string, options Options) string {
}
}

fn get_mime_type(file string, file_type os.FileType, is_exe bool) string {
if is_exe {
return 'application/octet-stream'
}
if file_type == .block_device || file_type == .character_device || file_type == .directory
|| file_type == .fifo || file_type == .symbolic_link || file_type == .socket {
return ''
}
mt := mime.get_mime_type(os.file_ext(file).trim_left('.'))
return mt
}

@[inline]
fn is_executable(stat os.Stat) bool {
return stat.get_mode().bitmask() & 0b001001001 > 0
Expand Down
68 changes: 31 additions & 37 deletions lsv/format_long.v
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const date_modified_title = 'Modified'
const date_accessed_title = 'Accessed'
const date_status_title = 'Status Change'
const name_title = 'Name'
const mime_type_title = 'Mime Type'
const unknown = '?'
const block_size = 5
const space = ' '
Expand All @@ -34,6 +35,7 @@ struct Longest {
mtime int
atime int
ctime int
mime_type int
}

enum StatTime {
Expand Down Expand Up @@ -69,10 +71,16 @@ fn format_long_listing(entries []Entry, options Options) {
print(table_border_pad_left)
}

// mime type
if options.mime_type {
print(format_cell(entry.mime_type, longest.mime_type, .right, no_style, options))
print_space()
}

// inode
if options.inode {
content := if entry.invalid { unknown } else { entry.stat.inode.str() }
print(format_cell(content, longest.inode, Align.right, no_style, options))
print(format_cell(content, longest.inode, .right, no_style, options))
print_space()
}

Expand Down Expand Up @@ -200,44 +208,19 @@ fn format_long_listing(entries []Entry, options Options) {

fn longest_entries(entries []Entry, options Options) Longest {
return Longest{
// vfmt off
inode: if options.inode { longest_inode_len(entries, inode_title, options) } else { 0 }
nlink: if !options.no_hard_links {
longest_nlink_len(entries, links_title, options)
} else {
0
}
owner_name: if !options.no_owner_name {
longest_owner_name_len(entries, owner_title, options)
} else {
0
}
group_name: if !options.no_group_name {
longest_group_name_len(entries, group_title, options)
} else {
0
}
nlink: if !options.no_hard_links { longest_nlink_len(entries, links_title, options) } else { 0 }
owner_name: if !options.no_owner_name { longest_owner_name_len(entries, owner_title, options) } else { 0 }
group_name: if !options.no_group_name { longest_group_name_len(entries, group_title, options) } else { 0 }
size: if !options.no_size { longest_size_len(entries, size_title, options) } else { 0 }
checksum: if options.checksum.len == 0 {
longest_checksum_len(entries, options.checksum, options)
} else {
0
}
checksum: if options.checksum.len == 0 { longest_checksum_len(entries, options.checksum, options) } else { 0 }
file: longest_file_name_len(entries, name_title, options)
mtime: if !options.no_date {
longest_time(entries, .modified, date_modified_title, options)
} else {
0
}
atime: if options.accessed_date {
longest_time(entries, .accessed, date_accessed_title, options)
} else {
0
}
ctime: if options.changed_date {
longest_time(entries, .changed, date_status_title, options)
} else {
0
}
mtime: if !options.no_date { longest_time(entries, .modified, date_modified_title, options) } else { 0 }
atime: if options.accessed_date { longest_time(entries, .accessed, date_accessed_title, options) } else { 0 }
ctime: if options.changed_date { longest_time(entries, .changed, date_status_title, options) } else { 0 }
mime_type: if options.mime_type { longest_mime_type(entries, mime_type_title, options) } else { 0 }
// vfmt on
}
}

Expand All @@ -259,6 +242,11 @@ fn format_header(options Options, longest Longest) (string, []int) {
if options.table_format {
buffer += table_border_pad_left
}
if options.mime_type {
title := if options.header { mime_type_title } else { '' }
buffer += right_pad(title, longest.mime_type) + table_pad
cols << real_length(buffer) - 1
}
if options.inode {
title := if options.header { inode_title } else { '' }
buffer += left_pad(title, longest.inode) + table_pad
Expand Down Expand Up @@ -439,7 +427,7 @@ fn format_time(entry Entry, stat_time StatTime, options Options) string {
date := if options.time_relative {
local.relative_short()
} else {
mut dt := local.custom_format(time_format(options))
dt := local.custom_format(time_format(options))
if dt.starts_with('0') {
' ' + dt[1..]
} else {
Expand Down Expand Up @@ -507,3 +495,9 @@ fn longest_time(entries []Entry, stat_time StatTime, title string, options Optio
max := arrays.max(lengths) or { 0 }
return if options.header { max(real_length(title), max) } else { max }
}

fn longest_mime_type(entries []Entry, title string, options Options) int {
mime_types := entries.map(it.mime_type.len)
max := arrays.max(mime_types) or { 0 }
return if options.header { max(real_length(title), max) } else { max }
}
3 changes: 3 additions & 0 deletions lsv/options.v
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct Options {
time_compact bool
time_compact_with_day bool
time_relative bool
mime_type bool
checksum string
//
// from ls colors
Expand Down Expand Up @@ -127,6 +128,7 @@ fn parse_args(args []string) Options {
time_compact := fp.bool('', `J`, false, 'show time in compact format')
time_compact_with_day := fp.bool('', `L`, false, 'show time in compact format with week day')
time_relative := fp.bool('', `T`, false, 'show relative time')
mime_type := fp.bool('', `M`, false, 'show mime type')
inode := fp.bool('', `N`, false, 'show inodes')
no_wrap := fp.bool('', `Z`, false, 'do not wrap long lines\n')

Expand Down Expand Up @@ -166,6 +168,7 @@ fn parse_args(args []string) Options {
inode: inode
list_by_lines: list_by_lines
long_format: long_format
mime_type: mime_type
no_count: no_count
no_date: no_date
no_dim: no_dim
Expand Down

0 comments on commit 5c04bca

Please sign in to comment.