v

Зеркало из https://github.com/vlang/v
Форк
0
/
help.v 
164 строки · 4.4 Кб
1
module cli
2

3
import term
4
import strings
5

6
const base_indent_len = 2
7
const min_description_indent_len = 20
8
const spacing = 2
9

10
fn help_flag(with_abbrev bool) Flag {
11
	sabbrev := if with_abbrev { 'h' } else { '' }
12
	return Flag{
13
		flag:        .bool
14
		name:        'help'
15
		abbrev:      sabbrev
16
		description: 'Prints help information.'
17
	}
18
}
19

20
fn help_cmd() Command {
21
	return Command{
22
		name:        'help'
23
		usage:       '<command>'
24
		description: 'Prints help information.'
25
		execute:     print_help_for_command
26
	}
27
}
28

29
// print_help_for_command outputs the help message of `help_cmd`.
30
pub fn print_help_for_command(cmd Command) ! {
31
	if cmd.args.len > 0 {
32
		for sub_cmd in cmd.commands {
33
			if sub_cmd.name == cmd.args[0] {
34
				cmd_ := unsafe { &sub_cmd }
35
				print(cmd_.help_message())
36
				return
37
			}
38
		}
39
		print('Invalid command: ${cmd.args.join(' ')}')
40
	} else if cmd.parent != unsafe { nil } {
41
		print(cmd.parent.help_message())
42
	}
43
}
44

45
// help_message returns a generated help message as a `string` for the `Command`.
46
pub fn (cmd Command) help_message() string {
47
	mut help := ''
48
	help += 'Usage: ${cmd.full_name()}'
49
	if cmd.flags.len > 0 {
50
		help += ' [flags]'
51
	}
52
	if cmd.commands.len > 0 {
53
		help += ' [commands]'
54
	}
55
	if cmd.usage.len > 0 {
56
		help += ' ${cmd.usage}'
57
	} else {
58
		for i in 0 .. cmd.required_args {
59
			help += ' <arg${i}>'
60
		}
61
	}
62
	help += '\n'
63
	if cmd.description != '' {
64
		help += '\n${cmd.description}\n'
65
	}
66
	mut abbrev_len := 0
67
	mut name_len := min_description_indent_len
68
	if cmd.posix_mode {
69
		for flag in cmd.flags {
70
			if flag.abbrev != '' {
71
				abbrev_len = max(abbrev_len, flag.abbrev.len + spacing + 1) // + 1 for '-' in front
72
			}
73
			name_len = max(name_len, abbrev_len + flag.name.len + spacing + 2) // + 2 for '--' in front
74
		}
75
		for command in cmd.commands {
76
			name_len = max(name_len, command.name.len + spacing)
77
		}
78
	} else {
79
		for flag in cmd.flags {
80
			if flag.abbrev != '' {
81
				abbrev_len = max(abbrev_len, flag.abbrev.len + spacing + 1) // + 1 for '-' in front
82
			}
83
			name_len = max(name_len, abbrev_len + flag.name.len + spacing + 1) // + 1 for '-' in front
84
		}
85
		for command in cmd.commands {
86
			name_len = max(name_len, command.name.len + spacing)
87
		}
88
	}
89
	if cmd.flags.len > 0 {
90
		help += '\nFlags:\n'
91
		for flag in cmd.flags {
92
			mut flag_name := ''
93
			prefix := if cmd.posix_mode { '--' } else { '-' }
94
			if flag.abbrev != '' {
95
				abbrev_indent := ' '.repeat(abbrev_len - flag.abbrev.len - 1) // - 1 for '-' in front
96
				flag_name = '-${flag.abbrev}${abbrev_indent}${prefix}${flag.name}'
97
			} else {
98
				abbrev_indent := ' '.repeat(abbrev_len)
99
				flag_name = '${abbrev_indent}${prefix}${flag.name}'
100
			}
101
			mut required := ''
102
			if flag.required {
103
				required = ' (required)'
104
			}
105
			base_indent := ' '.repeat(base_indent_len)
106
			description_indent := ' '.repeat(name_len - flag_name.len)
107
			help += '${base_indent}${flag_name}${description_indent}' +
108
				pretty_description(flag.description + required, base_indent_len + name_len) + '\n'
109
		}
110
	}
111
	if cmd.commands.len > 0 {
112
		help += '\nCommands:\n'
113
		for command in cmd.commands {
114
			base_indent := ' '.repeat(base_indent_len)
115
			description_indent := ' '.repeat(name_len - command.name.len)
116
			help += '${base_indent}${command.name}${description_indent}' +
117
				pretty_description(command.description, name_len) + '\n'
118
		}
119
	}
120
	return help
121
}
122

123
// pretty_description resizes description text depending on terminal width.
124
// Essentially, smart wrap-around
125
fn pretty_description(s string, indent_len int) string {
126
	width, _ := term.get_terminal_size()
127
	// Don't prettify if the terminal is that small, it won't be pretty anyway.
128
	if indent_len > width {
129
		return s
130
	}
131
	indent := ' '.repeat(indent_len)
132
	chars_per_line := width - indent_len
133
	// Give us enough room, better a little bigger than smaller
134
	mut acc := strings.new_builder(((s.len / chars_per_line) + 1) * (width + 1))
135
	for k, line in s.split('\n') {
136
		if k != 0 {
137
			acc.write_string('\n${indent}')
138
		}
139
		mut i := chars_per_line - 2
140
		mut j := 0
141
		for ; i < line.len; i += chars_per_line - 2 {
142
			for j > 0 && line[j] != ` ` {
143
				j--
144
			}
145
			// indent was already done the first iteration
146
			if j != 0 {
147
				acc.write_string(indent)
148
			}
149
			acc.writeln(line[j..i].trim_space())
150
			j = i
151
		}
152
		// We need this even though it should never happen
153
		if j != 0 {
154
			acc.write_string(indent)
155
		}
156
		acc.write_string(line[j..].trim_space())
157
	}
158
	return acc.str()
159
}
160

161
fn max(a int, b int) int {
162
	res := if a > b { a } else { b }
163
	return res
164
}
165

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.