rofi_plugin_sys/helper.rs
1//! Helper utilities.
2//!
3//! This corresponds to `helper.h`.
4
5use {
6 crate::{ConfigEntry, Property, PropertyType, RofiIntMatcher, RofiRangePair},
7 ::std::{
8 os::raw::{c_char, c_int, c_long, c_uint},
9 ptr::NonNull,
10 },
11};
12
13extern "C" {
14 /// Parses a string into arguments, replacing keys with values.
15 ///
16 /// Returns true if successful, false if it failed.
17 ///
18 /// - `string`: The input string.
19 /// - `output`: Pointer to 2-dimensional array with parsed string.
20 /// - `length`: Length of 2-dimensional array.
21 /// - `...`: Key, value parse. Replace the string key with value.
22 #[link_name = "helper_parse_setup"]
23 pub fn parse_setup(string: *mut c_char, output: *mut *mut *mut c_char, length: *mut c_int, ...);
24
25 /// Tokenize the string on spaces.
26 ///
27 /// Returns a newly allocated array of matching objects.
28 #[link_name = "helper_tokenize"]
29 pub fn tokenize(input: *const c_char, case_sensitive: c_int) -> *mut *mut RofiIntMatcher;
30
31 /// Frees the array of matching objects.
32 #[link_name = "helper_tokenize_free"]
33 pub fn tokenize_free(tokens: *mut *mut RofiIntMatcher);
34
35 /// Parse command line argument `key` to character.
36 /// This supports character escaping.
37 ///
38 /// Returns true if the key was found and `val` was set.
39 ///
40 /// - `key`: The key to search for.
41 /// - `val`: Pointer to the string to set to the key value (if found).
42 pub fn find_arg_char(key: *const c_char, val: *mut c_char) -> c_int;
43
44 /// Parse command line argument `key` to unsigned int.
45 ///
46 /// Returns true if key was found and `val` was set.
47 ///
48 /// - `key`: The key to search for.
49 /// - `val`: Pointer to the string to set to the key value (if found).
50 pub fn find_arg_uint(key: *const c_char, val: *mut c_uint) -> c_int;
51
52 /// Parse command line argument `key` to int.
53 ///
54 /// Returns true if key was found and `val` was set.
55 ///
56 /// - `key`: The key to search for.
57 /// - `val`: Pointer to the string to set to the key value (if found).
58 pub fn find_arg_int(key: *const c_char, val: *mut c_int) -> c_int;
59
60 /// Parse command line argument `key` to string.
61 ///
62 /// Returns true if key was found and `val` was set.
63 ///
64 /// - `key`: The key to search for.
65 /// - `val`: Pointer to the string to set to the key value (if found).
66 pub fn find_arg_str(key: *const c_char, val: *mut *mut c_char) -> c_int;
67
68 /// Parse all command line options `key` to string vector.
69 ///
70 /// Returns a string vector which the user must free.
71 pub fn find_arg_strv(key: *const c_char) -> *mut *const c_char;
72
73 /// Check if key is passed as argument.
74 ///
75 /// Returns position of string or -1 if not found.
76 pub fn find_arg(key: *const c_char) -> c_int;
77
78 /// Tokenized match, match tokens to line input.
79 ///
80 /// Returns true when matches, false otherwise.
81 ///
82 /// - `tokens`: List of input tokens to match.
83 /// - `input`: The entry to match against.
84 #[link_name = "helper_token_match"]
85 pub fn token_match(tokens: *const *mut RofiIntMatcher, input: *const c_char) -> c_int;
86
87 /// Execute cmd using `config.run_command` and outputs the result (stdout) to the opened file
88 /// descriptor.
89 ///
90 /// Returns a valid file descriptor on success, or -1 on failure.
91 pub fn execute_generator(cmd: *const c_char) -> c_int;
92
93 /// Returns file descriptor (or -1 when failed).
94 ///
95 /// - `pidfile`: The pidfile to create.
96 /// - `kill`: Try killing running instance.
97 pub fn create_pid_file(pidfile: *const c_char, kill: glib_sys::gboolean) -> c_int;
98
99 /// Remove pid file.
100 pub fn remove_pid_file(fd: c_int);
101
102 /// Do some input validation, especially the first few could break things. It is good to catch
103 /// them beforehand.
104 ///
105 /// This function exits the program with 1 when it finds an invalid configuration.
106 pub fn config_sanity_check() -> c_int;
107
108 /// Parses a string into a character.
109 #[link_name = "helper_parse_char"]
110 pub fn parse_char(arg: *const c_char) -> c_char;
111
112 /// Set the application arguments.
113 pub fn cmd_set_arguments(argc: c_int, argv: *mut *mut c_char);
114
115 /// Expand path, both `~` and `~<user>`.
116 #[link_name = "rofi_expand_path"]
117 pub fn expand_path(input: *const c_char) -> *const c_char;
118
119 /// UTF-8 aware levenshtein distance calculation.
120 ///
121 /// - `needle`: The string to match weight off
122 /// - `needlelen`: The length of the needle
123 /// - `haystack`: The string to match against
124 /// - `haystacklen`: The length of the haystack
125 /// - `case_sensitive`: Whether case is significant.
126 pub fn levenshtein(
127 needle: *const c_char,
128 needlelen: c_long,
129 haystack: *const c_char,
130 haystacklen: c_long,
131 case_sensitive: c_int,
132 ) -> c_uint;
133
134 /// Convert string to valid UTF-8, replacing invalid parts with replacement character.
135 ///
136 /// - `data`: The unvalidated character array holding possible UTF-8 data
137 /// - `length`: The length of `data`
138 #[link_name = "rofi_force_utf8"]
139 pub fn force_utf8(data: *const c_char, length: isize) -> *const c_char;
140
141 /// Converts latin to UTF-8.
142 #[link_name = "rofi_latin_to_utf8_strdup"]
143 pub fn latin_to_utf8_strdup(input: *const c_char, length: isize) -> *const c_char;
144
145 /// Run Rofi's global sequence alignment algorithm to find the maximum accumulated score by
146 /// aligning `pattern` to `str`.
147 /// It applies when `pattern` is a subsequence of `str`.
148 ///
149 /// Scoring criteria
150 /// - Prefer matches at the start of a word, or the start of subwords in
151 /// CamelCase/camelCase/camel123 words. See WORD_START_SCORE/CAMEL_SCORE.
152 /// - Non-word characters matter. See NON_WORD_SCORE.
153 /// - The first characters of words of `pattern` receive bonus because they usually have more
154 /// significance than the rest. See PATTERN_START_MULTIPLIER/PATTERN_NON_START_MULTIPLIER.
155 /// - Superfluous characters in `str` will reduce the score (gap penalty). See GAP_SCORE.
156 /// - Prefer early occurrence of the first character. See LEADING_GAP_SCORE/GAP_SCORE.
157 ///
158 /// The recurrence of the dynamic programming:
159 /// - `dp[i][j]`: maximum accumulated score by aligning `pattern[0..i]` to `str[0..j]`
160 /// - `dp[0][j] = leading_gap_penalty(0, j) + score[j]`
161 /// - `dp[i][j] = max(dp[i-1][j-1] + CONSECUTIVE_SCORE, max(dp[i-1][k] + gap_penalty(k+1, j) + score[j] : k < j))`
162 ///
163 /// The first dimension can be suppressed since we do not need a matching scheme, which reduces
164 /// the space complexity from O(N*M) to O(M)
165 ///
166 /// Returns the sorting weight.
167 ///
168 /// - `pattern`: The user input to match against.
169 /// - `plen`: The length of `pattern`.
170 /// - `str`: The input to match against `pattern`.
171 /// - `slen`: Length of `str`.
172 /// - `case_sensitive`: Whether case is significant.
173 #[link_name = "rofi_scorer_fuzzy_evaluate"]
174 pub fn scorer_fuzzy_evaluate(
175 pattern: *const c_char,
176 plen: c_long,
177 str: *const c_char,
178 slen: c_long,
179 case_sensitive: c_int,
180 ) -> c_int;
181
182 /// Compares the `G_NORMALIZE_ALL_COMPOSE` forms of the two strings.
183 ///
184 /// Returns less than, equal to, or greater than zero if the first `n` characters (not bytes) of
185 /// `a` are found, respectively, to be less than, to match, or be greater than the first `n`
186 /// characters (not bytes) of `b`.
187 ///
188 /// - `a`: First UTF-8 string to compare, non-null.
189 /// - `b`: Second UTF-8 string to compare, non-null.
190 /// - `n`: Maximum number of characters to compare.
191 pub fn utf8_strncmp(a: *const c_char, b: *const c_char, n: usize) -> c_int;
192}
193
194/// The startup notification context of the application to launch.
195#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
196#[repr(C)]
197pub struct RofiHelperExecuteContext {
198 /// The name of the application.
199 pub name: *const c_char,
200 /// The binary name of the application.
201 pub binary: *const c_char,
202 /// The description of the launch.
203 pub description: *const c_char,
204 /// The icon name of the application.
205 pub icon: *const c_char,
206 /// The application ID (desktop file with the `.desktop` suffix).
207 pub app_id: *const c_char,
208 /// The window manager class of the application.
209 pub wmclass: *const c_char,
210 /// The command we run.
211 pub command: *const c_char,
212}
213
214extern "C" {
215 /// Executes the comand.
216 ///
217 /// Returns true when successful, false otherwise.
218 ///
219 /// - `wd`: The working directory.
220 /// - `args`: The argments of the command to exec.
221 /// - `error_precmd`: Prefix to error message command.
222 /// - `error_cmd`: Error message command.
223 /// - `context`: The startup notification context, if any.
224 #[link_name = "helper_execute"]
225 pub fn execute(
226 wd: *const c_char,
227 args: *mut *mut c_char,
228 error_precmd: *const c_char,
229 error_cmd: *const c_char,
230 context: *mut RofiHelperExecuteContext,
231 ) -> glib_sys::gboolean;
232
233 /// Executes the comand.
234 /// If needed memebrs of `context` are null, they will be filled.
235 ///
236 /// Returns true when successful, false otherwise.
237 ///
238 /// - `wd`: The working directory (optional).
239 /// - `cmd`: The command to execute.
240 /// - `run_in_term`: Indicates if the command should be run in a terminal.
241 /// - `context`: The startup notification context, if any.
242 #[link_name = "helper_execute_command"]
243 pub fn execute_command(
244 wd: *const c_char,
245 cmd: *const c_char,
246 run_in_term: glib_sys::gboolean,
247 context: *mut RofiHelperExecuteContext,
248 ) -> glib_sys::gboolean;
249
250 /// Get a cairo surface from an SVG path.
251 ///
252 /// - `param`: The file path.
253 /// - `height`: The wanted height.
254 pub fn cairo_image_surface_create_from_svg(
255 file: *const c_char,
256 height: c_int,
257 ) -> *mut cairo_sys::cairo_surface_t;
258
259 /// Parse ranges.
260 ///
261 /// - `input`: String to parse.
262 /// - `list`: List of ranges.
263 /// - `length`: Length of list.
264 pub fn parse_ranges(input: *mut c_char, list: *mut *mut RofiRangePair, length: *mut c_uint);
265
266 /// Get whether string matching should be case sensitive or insensitive.
267 ///
268 /// - `input`: String to parse.
269 pub fn parse_case_sensitivity(input: *const c_char) -> c_int;
270
271 /// This functions outputs the formatted string to stdout, appends a newline (`\n`)
272 /// character and calls flush on the file descriptor.
273 ///
274 /// - `format`: The format string used. See below for possible syntax.
275 /// - `string`: The selected entry.
276 /// - `selected_line`: The selected line index.
277 /// - `filter`: The entered filter.
278 ///
279 /// Currently the following formats are supported:
280 /// - i: Print the index (0-(N-1))
281 /// - d: Print the index (1-N)
282 /// - s: Print input string.
283 /// - q: Print quoted input string.
284 /// - f: Print the entered filter.
285 /// - F: Print the entered filter, quoted
286 #[link_name = "rofi_output_formatted_line"]
287 pub fn output_formatted_line(
288 format: *const c_char,
289 string: *const c_char,
290 selected_line: c_int,
291 filter: *const c_char,
292 );
293
294 /// Items {key} are replaced by the value if `{key}` is passed as key/value pair, otherwise
295 /// removed from string. If the {key} is in between [] all the text between [] are removed if
296 /// {key} is not found. Otherwise key is replaced and [ & ] removed.
297 ///
298 /// This allows for optional replacement, e.g. `{ssh-client} [-t {title}] -e "{cmd}"` the `-t
299 /// {title}` is only there if {title} is set.
300 ///
301 /// Returns a new string with the keys replaced.
302 ///
303 /// - `string`: The string with elements to be replaced.
304 /// - `...`: Set of {key}, value that will be replaced, terminated by a null.
305 #[link_name = "helper_string_replace_if_exists"]
306 pub fn string_replace_if_exists(string: *mut c_char, ...) -> *mut c_char;
307
308 /// Returns path to theme or copy of filename if not found.
309 ///
310 /// - `file`: File name passed to option.
311 /// - `ext`: null-terminated array of file extensions.
312 /// - `parent_dir`: the file that was used to import this file, or NULL.
313 #[link_name = "helper_get_theme_path"]
314 pub fn get_theme_path(
315 file: NonNull<c_char>,
316 ext: NonNull<*const c_char>,
317 parent_dir: *const c_char,
318 ) -> *mut c_char;
319
320 /// Find the configuration element.
321 /// If not exact, the closest specified element is returned.
322 /// Returns the [`ThemeWidget`](crate::ThemeWidget) if found, otherwise null.
323 ///
324 /// - `name`: The name of the element to find.
325 /// - `state`: The state of the element.
326 /// - `exact`: If the match should be exact, or the parent can be included.
327 #[link_name = "rofi_config_find_widget"]
328 pub fn config_find_widget(
329 name: *const c_char,
330 state: *const c_char,
331 exact: glib_sys::gboolean,
332 ) -> *mut ConfigEntry;
333
334 /// Find the property on the widget.
335 /// If not exact, the parents are searched recursively until match is found.
336 /// Returns the [`Property`] if found, otherwise null.
337 ///
338 /// - `widget`: The widget to find the property on.
339 /// - `type`: The [`PropertyType`] to find.
340 /// - `property`: The property to find.
341 /// - `exact`: If the property should only be found on this widget, or on parents if not found.
342 #[link_name = "rofi_theme_find_property"]
343 pub fn theme_find_property(
344 widget: *mut ConfigEntry,
345 r#type: PropertyType,
346 property: *const c_char,
347 exact: glib_sys::gboolean,
348 ) -> *mut Property;
349
350 /// Get a human-readable string with the current matching method.
351 pub fn helper_get_matching_mode_str() -> *const c_char;
352
353 /// Switch to the next matching method.
354 pub fn helper_select_next_matching_mode();
355
356 /// Switch to the previous matching method.
357 pub fn helper_select_previous_matching_mode();
358}