Merge remote-tracking branch 'upstream/next' into wayland
This commit is contained in:
4
.github/workflows/codeql.yml
vendored
4
.github/workflows/codeql.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -52,6 +52,6 @@ jobs:
|
||||
cc: gcc
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
@@ -182,6 +182,7 @@ if FOUND_PANDOC
|
||||
generate-manpage: doc/rofi.1\
|
||||
doc/rofi-sensible-terminal.1\
|
||||
doc/rofi-theme-selector.1\
|
||||
doc/rofi-actions.5\
|
||||
doc/rofi-debugging.5\
|
||||
doc/rofi-dmenu.5\
|
||||
doc/rofi-keys.5\
|
||||
|
@@ -49,6 +49,18 @@ Settings config = {
|
||||
/** Custom command to generate preview icons */
|
||||
.preview_cmd = NULL,
|
||||
|
||||
/** Custom command to call when menu selection changes */
|
||||
.on_selection_changed = NULL,
|
||||
/** Custom command to call when menu mode changes */
|
||||
.on_mode_changed = NULL,
|
||||
/** Custom command to call when menu entry is accepted */
|
||||
.on_entry_accepted = NULL,
|
||||
/** Custom command to call when menu is canceled */
|
||||
.on_menu_canceled = NULL,
|
||||
/** Custom command to call when menu finds errors */
|
||||
.on_menu_error = NULL,
|
||||
/** Custom command to call when menu screenshot is taken */
|
||||
.on_screenshot_taken = NULL,
|
||||
/** Terminal to use. (for ssh and open in terminal) */
|
||||
.terminal_emulator = "rofi-sensible-terminal",
|
||||
.ssh_client = "ssh",
|
||||
@@ -92,6 +104,8 @@ Settings config = {
|
||||
.sorting_method = "normal",
|
||||
/** Case sensitivity of the search */
|
||||
.case_sensitive = FALSE,
|
||||
/** Case smart of the search */
|
||||
.case_smart = FALSE,
|
||||
/** Cycle through in the element list */
|
||||
.cycle = TRUE,
|
||||
/** Height of an element in #chars */
|
||||
|
@@ -1,4 +1,4 @@
|
||||
AC_INIT([rofi], [1.7.8], [https://github.com/davatorium/rofi/],[],[https://github.com/davatorium/rofi/discussions])
|
||||
AC_INIT([rofi], [1.7.8-dev], [https://github.com/davatorium/rofi/],[],[https://github.com/davatorium/rofi/discussions])
|
||||
|
||||
AC_CONFIG_SRCDIR([source/rofi.c])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
|
@@ -141,10 +141,17 @@ textbox-num-sep {
|
||||
str: "/";
|
||||
}
|
||||
inputbar {
|
||||
padding: 1px ;
|
||||
spacing: 0px ;
|
||||
padding: 1px;
|
||||
spacing: 0px;
|
||||
text-color: var(normal-foreground);
|
||||
children: [ prompt,textbox-prompt-colon,entry, num-filtered-rows, textbox-num-sep, num-rows, case-indicator ];
|
||||
children: [ prompt,textbox-prompt-colon,entry, overlay,num-filtered-rows, textbox-num-sep, num-rows, case-indicator ];
|
||||
}
|
||||
overlay {
|
||||
background-color: var(normal-foreground);
|
||||
foreground-color: var(normal-background);
|
||||
text-color: var(normal-background);
|
||||
padding: 0 0.2em;
|
||||
margin: 0 0.2em;
|
||||
}
|
||||
case-indicator {
|
||||
spacing: 0;
|
||||
|
@@ -2,6 +2,7 @@ man_files = [
|
||||
'rofi.1',
|
||||
'rofi-sensible-terminal.1',
|
||||
'rofi-theme-selector.1',
|
||||
'rofi-actions.5',
|
||||
'rofi-debugging.5',
|
||||
'rofi-dmenu.5',
|
||||
'rofi-keys.5',
|
||||
|
89
doc/rofi-actions.5.markdown
Normal file
89
doc/rofi-actions.5.markdown
Normal file
@@ -0,0 +1,89 @@
|
||||
# rofi-actions(5)
|
||||
|
||||
## NAME
|
||||
|
||||
**rofi-actions** - Custom commands following interaction with rofi menus
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
**rofi** allows to set custom commands or scripts to be executed when some actions are performed in the menu, such as changing selection, accepting an entry or canceling.
|
||||
|
||||
This makes it possible for example to play sound effects or read aloud menu entries on selection.
|
||||
|
||||
## USAGE
|
||||
|
||||
Following is the list of rofi flags for specifying custom commands or scripts to execute on supported actions:
|
||||
|
||||
`-on-selection-changed` *cmd*
|
||||
|
||||
Command or script to run when the current selection changes. Selected text is forwarded to the command replacing the pattern *{entry}*.
|
||||
|
||||
`-on-entry-accepted` *cmd*
|
||||
|
||||
Command or script to run when a menu entry is accepted. Accepted text is forwarded to the command replacing the pattern *{entry}*.
|
||||
|
||||
`-on-mode-changed` *cmd*
|
||||
|
||||
Command or script to run when the menu mode (e.g. drun,window,ssh...) is changed.
|
||||
|
||||
`-on-menu-canceled` *cmd*
|
||||
|
||||
Command or script to run when the menu is canceled.
|
||||
|
||||
`-on-menu-error` *cmd*
|
||||
|
||||
Command or script to run when an error menu is shown (e.g. `rofi -e "error message"`). Error text is forwarded to the command replacing the pattern *{error}*.
|
||||
|
||||
`-on-screenshot-taken` *cmd*
|
||||
|
||||
Command or script to run when a screenshot of rofi is taken. Screenshot path is forwarded to the command replacing the pattern *{path}*.
|
||||
|
||||
### Example usage
|
||||
|
||||
Rofi command line:
|
||||
|
||||
```bash
|
||||
rofi -on-selection-changed "/path/to/select.sh {entry}" \
|
||||
-on-entry-accepted "/path/to/accept.sh {entry}" \
|
||||
-on-menu-canceled "/path/to/exit.sh" \
|
||||
-on-mode-changed "/path/to/change.sh" \
|
||||
-on-menu-error "/path/to/error.sh {error}" \
|
||||
-on-screenshot-taken "/path/to/camera.sh {path}" \
|
||||
-show drun
|
||||
```
|
||||
|
||||
Rofi config file:
|
||||
|
||||
```css
|
||||
configuration {
|
||||
on-selection-changed: "/path/to/select.sh {entry}";
|
||||
on-entry-accepted: "/path/to/accept.sh {entry}";
|
||||
on-menu-canceled: "/path/to/exit.sh";
|
||||
on-mode-changed: "/path/to/change.sh";
|
||||
on-menu-error: "/path/to/error.sh {error}";
|
||||
on-screenshot-taken: "/path/to/camera.sh {path}";
|
||||
}
|
||||
```
|
||||
|
||||
### Play sound effects
|
||||
|
||||
Here's an example bash script that plays a sound effect using `aplay` when the current selection is changed:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
coproc aplay -q $HOME/Music/selecting_an_item.wav
|
||||
```
|
||||
|
||||
The use of `coproc` for playing sounds is suggested, otherwise the rofi process will wait for sounds to end playback before exiting.
|
||||
|
||||
### Read aloud
|
||||
|
||||
Here's an example bash script that reads aloud currently selected entries using `espeak`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
killall espeak
|
||||
echo "selected: $@" | espeak
|
||||
```
|
@@ -159,7 +159,7 @@ Hide the input text. This should not be considered secure!
|
||||
`-markup-rows`
|
||||
|
||||
Tell **rofi** that DMenu input is Pango markup encoded, and should be rendered.
|
||||
See [here](https://developer.gnome.org/pygtk/stable/pango-markup-language.html)
|
||||
See [here](https://docs.gtk.org/Pango/pango_markup.html)
|
||||
for details about Pango markup.
|
||||
|
||||
`-multi-select`
|
||||
|
@@ -495,6 +495,18 @@ Go down in the entry history.
|
||||
|
||||
Default: Control+Down
|
||||
|
||||
`kb-matcher-up`
|
||||
|
||||
Select the next matcher.
|
||||
|
||||
Default: Super+equal
|
||||
|
||||
`kb-matcher-down`
|
||||
|
||||
Select the previous matcher.
|
||||
|
||||
Default: Super+minus
|
||||
|
||||
## Mouse Bindings
|
||||
|
||||
`ml-row-left`
|
||||
|
@@ -59,6 +59,7 @@ An integer number with the current state:
|
||||
- **0**: Initial call of script.
|
||||
- **1**: Selected an entry.
|
||||
- **2**: Selected a custom entry.
|
||||
- **3**: Deleted an entry.
|
||||
- **10-28**: Custom keybinding 1-19 ( need to be explicitly enabled by script ).
|
||||
|
||||
### `ROFI_INFO`
|
||||
|
@@ -1118,6 +1118,10 @@ The following properties are currently supported:
|
||||
- **require-input**: boolean Listview requires user input to be unhidden.
|
||||
The list is still present and hitting accept will activate the first entry.
|
||||
|
||||
### Overlay widget
|
||||
|
||||
- **timeout**: The time the widget is visible when showing a temporary message.
|
||||
|
||||
## Listview widget
|
||||
|
||||
The listview widget is special container widget.
|
||||
@@ -1658,6 +1662,14 @@ If a filename is provided, it will try to resolve it in the following order:
|
||||
A name is resolved (if it has no valid extension) as a filename by appending the `.rasi` and the `.rasinc` extension.
|
||||
It will first look for files with `.rasi`, then for files with `.rasinc`.
|
||||
|
||||
If you want to do an optional import, e.g. no error when the file does not exists, you can do:
|
||||
|
||||
```css
|
||||
?import "myfile"
|
||||
```
|
||||
|
||||
This still throws an error on syntax error, but won't abort parsing if file does not exists.
|
||||
|
||||
## Examples
|
||||
|
||||
Several examples are installed together with **rofi**. These can be found in
|
||||
|
@@ -246,6 +246,12 @@ exec command. For that case, `#` can be used as a separator.
|
||||
Start in case-sensitive mode. This option can be changed at run-time using the
|
||||
`-kb-toggle-case-sensitivity` key binding.
|
||||
|
||||
`-case-smart`
|
||||
|
||||
Start in case-smart mode behave like vim's `smartcase`, which determines
|
||||
case-sensitivity by input. When enabled, this will suppress `-case-sensitive`
|
||||
config.
|
||||
|
||||
`-cycle`
|
||||
|
||||
Cycle through the result list. Default is 'true'.
|
||||
@@ -355,6 +361,9 @@ Currently, the following methods are supported:
|
||||
|
||||
Default: *normal*
|
||||
|
||||
Multiple matching methods can be specified in a comma separated list.
|
||||
The matching up/down keybinding allows cycling through at runtime.
|
||||
|
||||
Note: glob matching might be slow for larger lists
|
||||
|
||||
`-tokenize`
|
||||
|
@@ -200,13 +200,15 @@ char *rofi_expand_path(const char *input);
|
||||
* @param needlelen The length of the needle
|
||||
* @param haystack The string to match against
|
||||
* @param haystacklen The length of the haystack
|
||||
* @param case_sensitive Whether case is significant.
|
||||
*
|
||||
* UTF-8 aware levenshtein distance calculation
|
||||
*
|
||||
* @returns the levenshtein distance between needle and haystack
|
||||
*/
|
||||
unsigned int levenshtein(const char *needle, const glong needlelen,
|
||||
const char *haystack, const glong haystacklen);
|
||||
const char *haystack, const glong haystacklen,
|
||||
const int case_sensitive);
|
||||
|
||||
/**
|
||||
* @param data the unvalidated character array holding possible UTF-8 data
|
||||
@@ -234,6 +236,7 @@ char *rofi_latin_to_utf8_strdup(const char *input, gssize length);
|
||||
* @param plen Pattern length.
|
||||
* @param str The input to match against pattern.
|
||||
* @param slen Length of str.
|
||||
* @param case_sensitive Whether case is significant.
|
||||
*
|
||||
* rofi_scorer_fuzzy_evaluate implements a global sequence alignment algorithm
|
||||
* to find the maximum accumulated score by aligning `pattern` to `str`. It
|
||||
@@ -263,7 +266,7 @@ char *rofi_latin_to_utf8_strdup(const char *input, gssize length);
|
||||
* @returns the sorting weight.
|
||||
*/
|
||||
int rofi_scorer_fuzzy_evaluate(const char *pattern, glong plen, const char *str,
|
||||
glong slen);
|
||||
glong slen, const int case_sensitive);
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
@@ -353,6 +356,13 @@ cairo_surface_t *cairo_image_surface_create_from_svg(const gchar *file,
|
||||
*/
|
||||
void parse_ranges(char *input, rofi_range_pair **list, unsigned int *length);
|
||||
|
||||
/**
|
||||
* @param input String to parse
|
||||
*
|
||||
* @returns String matching should be case sensitive or insensitive
|
||||
*/
|
||||
int parse_case_sensitivity(const char *input);
|
||||
|
||||
/**
|
||||
* @param format The format string used. See below for possible syntax.
|
||||
* @param string The selected entry.
|
||||
@@ -432,6 +442,19 @@ ConfigEntry *rofi_config_find_widget(const char *name, const char *state,
|
||||
*/
|
||||
Property *rofi_theme_find_property(ConfigEntry *widget, PropertyType type,
|
||||
const char *property, gboolean exact);
|
||||
|
||||
/**
|
||||
* @returns get a human readable string with the current matching method.
|
||||
*/
|
||||
const char *helper_get_matching_mode_str(void);
|
||||
/**
|
||||
* Switch to the next matching method.
|
||||
*/
|
||||
void helper_select_next_matching_mode(void);
|
||||
/**
|
||||
* Switch to the previous matching method.
|
||||
*/
|
||||
void helper_select_previous_matching_mode(void);
|
||||
G_END_DECLS
|
||||
|
||||
/**@} */
|
||||
|
@@ -145,6 +145,8 @@ typedef enum {
|
||||
SELECT_ELEMENT_10,
|
||||
ENTRY_HISTORY_UP,
|
||||
ENTRY_HISTORY_DOWN,
|
||||
MATCHER_UP,
|
||||
MATCHER_DOWN
|
||||
} KeyBindingAction;
|
||||
|
||||
/**
|
||||
|
@@ -31,9 +31,6 @@
|
||||
#include <gmodule.h>
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/** ABI version to check if loaded plugin is compatible. */
|
||||
#define ABI_VERSION 7u
|
||||
|
||||
/**
|
||||
* Indicator what type of mode this is.
|
||||
* For now it can be the classic switcher, or also implement a completer.
|
||||
|
@@ -29,7 +29,12 @@
|
||||
#define ROFI_MODE_H
|
||||
#include "rofi-types.h"
|
||||
#include <cairo.h>
|
||||
#include <gmodule.h>
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/** ABI version to check if loaded plugin is compatible. */
|
||||
#define ABI_VERSION 7u
|
||||
|
||||
/**
|
||||
* @defgroup MODE Mode
|
||||
*
|
||||
@@ -277,6 +282,28 @@ ModeMode mode_completer_result(Mode *sw, int menu_retv, char **input,
|
||||
* @returns TRUE if mode can be used as completer.
|
||||
*/
|
||||
gboolean mode_is_completer(const Mode *sw);
|
||||
|
||||
/**
|
||||
* @param mode The mode to query
|
||||
*
|
||||
* @returns the modes ABI version.
|
||||
*/
|
||||
int mode_get_abi_version(Mode *const mode);
|
||||
|
||||
/**
|
||||
* @param mode The mode to query
|
||||
* @param mod The GModule used to load the mode
|
||||
*
|
||||
* Set GModule used to load this plugin, this is used to
|
||||
* unload it on shutdown.
|
||||
*/
|
||||
void mode_plugin_set_module(Mode *mode, GModule *mod);
|
||||
/**
|
||||
* @param mode The mode to query
|
||||
*
|
||||
* @returns the GModule used to load this plugin. NULL if not a plugin.
|
||||
*/
|
||||
GModule *mode_plugin_get_module(Mode *mode);
|
||||
/**@}*/
|
||||
G_END_DECLS
|
||||
#endif
|
||||
|
@@ -40,7 +40,8 @@ typedef enum {
|
||||
MM_REGEX = 1,
|
||||
MM_GLOB = 2,
|
||||
MM_FUZZY = 3,
|
||||
MM_PREFIX = 4
|
||||
MM_PREFIX = 4,
|
||||
MM_NUM_MATCHERS = 5
|
||||
} MatchingMethod;
|
||||
|
||||
/**
|
||||
@@ -69,6 +70,18 @@ typedef struct {
|
||||
/** Custom command to generate preview icons */
|
||||
char *preview_cmd;
|
||||
|
||||
/** Custom command to call when menu selection changes */
|
||||
char *on_selection_changed;
|
||||
/** Custom command to call when menu mode changes */
|
||||
char *on_mode_changed;
|
||||
/** Custom command to call when menu entry is accepted */
|
||||
char *on_entry_accepted;
|
||||
/** Custom command to call when menu is canceled */
|
||||
char *on_menu_canceled;
|
||||
/** Custom command to call when menu finds errors */
|
||||
char *on_menu_error;
|
||||
/** Custom command to call when menu screenshot is taken */
|
||||
char *on_screenshot_taken;
|
||||
/** Terminal to use */
|
||||
char *terminal_emulator;
|
||||
/** SSH client to use */
|
||||
@@ -123,6 +136,8 @@ typedef struct {
|
||||
|
||||
/** Search case sensitivity */
|
||||
unsigned int case_sensitive;
|
||||
/** Smart case sensitivity like vim */
|
||||
unsigned int case_smart;
|
||||
/** Cycle through in the element list */
|
||||
unsigned int cycle;
|
||||
/** Height of an element in number of rows */
|
||||
|
@@ -101,6 +101,8 @@ struct RofiViewState {
|
||||
int skip_absorb;
|
||||
/** The selected line (in the unfiltered list) */
|
||||
unsigned int selected_line;
|
||||
/** The previously selected line (in the unfiltered list) */
|
||||
unsigned int previous_line;
|
||||
/** The return state of the view */
|
||||
MenuReturn retv;
|
||||
/** Monitor #workarea the view is displayed on */
|
||||
@@ -159,12 +161,13 @@ struct RofiViewState {
|
||||
|
||||
/** Regexs used for matching */
|
||||
rofi_int_matcher **tokens;
|
||||
/** For case-sensitivity */
|
||||
gboolean case_sensitive;
|
||||
};
|
||||
/** @} */
|
||||
|
||||
typedef struct _view_proxy {
|
||||
void (*update)(struct RofiViewState *state, gboolean qr);
|
||||
void (*maybe_update)(struct RofiViewState *state);
|
||||
void (*temp_configure_notify)(struct RofiViewState *state,
|
||||
xcb_configure_notify_event_t *xce);
|
||||
void (*temp_click_to_exit)(struct RofiViewState *state, xcb_window_t target);
|
||||
@@ -222,6 +225,8 @@ struct _rofi_view_cache_state {
|
||||
gboolean delayed_mode;
|
||||
/** timeout handling */
|
||||
guint user_timeout;
|
||||
/** timeout overlay */
|
||||
guint overlay_timeout;
|
||||
/** Entry box */
|
||||
gboolean entry_history_enable;
|
||||
/** Array with history entriy input. */
|
||||
|
@@ -287,6 +287,14 @@ void rofi_view_switch_mode(RofiViewState *state, Mode *mode);
|
||||
* Overlays text over the current view. Passing NULL for text hides the overlay.
|
||||
*/
|
||||
void rofi_view_set_overlay(RofiViewState *state, const char *text);
|
||||
/**
|
||||
* @param state The handle to the view
|
||||
* @param text An UTF-8 encoded character array with the text to overlay.
|
||||
*
|
||||
* Overlays text over the current view. Passing NULL for text hides the overlay.
|
||||
* This message is automatically removed after X seconds.
|
||||
*/
|
||||
void rofi_view_set_overlay_timeout (RofiViewState *state, const char *text);
|
||||
|
||||
/**
|
||||
* @param state The handle to the view.
|
||||
|
@@ -80,7 +80,9 @@ typedef struct {
|
||||
TBFontConfig *tbfc;
|
||||
|
||||
PangoEllipsizeMode emode;
|
||||
//
|
||||
|
||||
const char *password_mask_char;
|
||||
|
||||
const char *theme_name;
|
||||
} textbox;
|
||||
|
||||
|
@@ -51,6 +51,8 @@
|
||||
int last_state = 0;
|
||||
extern int rofi_is_in_dmenu_mode;
|
||||
|
||||
gboolean import_optional = FALSE;
|
||||
|
||||
const char *rasi_theme_file_extensions[] = {".rasi", ".rasinc", NULL};
|
||||
/**
|
||||
* Type of Object to parse.
|
||||
@@ -289,6 +291,7 @@ C_COMMENT_OPEN "/*"
|
||||
|
||||
|
||||
INCLUDE "@import"
|
||||
OPT_INCLUDE "?import"
|
||||
THEME "@theme"
|
||||
DEFAULT (?i:\"default\"?)
|
||||
|
||||
@@ -378,6 +381,12 @@ if ( queue == NULL ) {
|
||||
*/
|
||||
<INITIAL>{INCLUDE} {
|
||||
g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );
|
||||
import_optional = FALSE;
|
||||
BEGIN(INCLUDE);
|
||||
}
|
||||
<INITIAL>{OPT_INCLUDE} {
|
||||
g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );
|
||||
import_optional = TRUE;
|
||||
BEGIN(INCLUDE);
|
||||
}
|
||||
<INITIAL>{THEME} {
|
||||
@@ -437,10 +446,15 @@ if ( queue == NULL ) {
|
||||
yylloc->first_column = yylloc->last_column = 1;
|
||||
yylloc->filename = current->filename;
|
||||
} else {
|
||||
if ( !import_optional ) {
|
||||
char *str = g_markup_printf_escaped ( "Failed to open theme: <i>%s</i>\nError: <b>%s</b>",
|
||||
filename, strerror ( errno ) );
|
||||
rofi_add_warning_message ( g_string_new ( str ) );
|
||||
g_free ( str );
|
||||
} else {
|
||||
g_warning("Trying to parse optional theme: '%s', Error: %s",
|
||||
filename, strerror(errno));
|
||||
}
|
||||
g_free(filename);
|
||||
}
|
||||
// Pop out of include. */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
project('rofi', 'c',
|
||||
version: '1.7.8+wayland1',
|
||||
version: '1.7.8+wayland1-dev',
|
||||
meson_version: '>=0.59.0',
|
||||
license: [ 'MIT' ],
|
||||
default_options: [
|
||||
|
36
mkdocs/docs/themes/capture.sh
vendored
36
mkdocs/docs/themes/capture.sh
vendored
@@ -3,9 +3,7 @@
|
||||
THEMES=../../../themes/*.rasi
|
||||
ROFI_BIN=../../../build/rofi
|
||||
|
||||
|
||||
function generate_options()
|
||||
{
|
||||
function generate_options() {
|
||||
echo -en "rofi\0icon\x1frofi\n"
|
||||
echo -en "help browser\0icon\x1fhelp-browser\n"
|
||||
echo -en "thunderbird\0icon\x1fthunderbird\n"
|
||||
@@ -17,41 +15,37 @@ function generate_options()
|
||||
echo -en "Quit\0icon\x1fapplication-exit\n"
|
||||
}
|
||||
|
||||
function run_theme
|
||||
{
|
||||
function run_theme {
|
||||
theme=$1
|
||||
BASE=$(basename ${theme})
|
||||
BASE="$(basename ${theme})"
|
||||
NAME=${BASE%.rasi}
|
||||
export ROFI_PNG_OUTPUT="${NAME}.png"
|
||||
if [ ${NAME} = "default" ]
|
||||
then
|
||||
echo "# Default theme" >> themes.md
|
||||
if [ "${NAME}" = "default" ]; then
|
||||
echo "# Default theme" >>themes.md
|
||||
else
|
||||
echo "# [${NAME}](https://github.com/davatorium/rofi/blob/next/themes/${BASE})" >> themes.md
|
||||
echo "# [${NAME}](https://github.com/davatorium/rofi/blob/next/themes/${BASE})" >>themes.md
|
||||
fi
|
||||
echo "" >> themes.md
|
||||
echo "" >>themes.md
|
||||
generate_options | ${ROFI_BIN} -theme-str "@theme \"${theme}\"" \
|
||||
-no-config -dmenu -p "mode" -show-icons \
|
||||
-u 3 -a 4 -mesg "Message box for extra information" \
|
||||
-take-screenshot-quit 1500
|
||||
|
||||
echo "" >> themes.md
|
||||
echo "" >> themes.md
|
||||
echo "" >>themes.md
|
||||
echo "" >>themes.md
|
||||
}
|
||||
|
||||
echo "# Included Themes" > themes.md
|
||||
|
||||
echo "Below is a list of themes shipped with rofi." >> themes.md
|
||||
echo "Use \`rofi-theme-selector\` to select and use one of these themes." >> themes.md
|
||||
echo "# Included Themes" >themes.md
|
||||
|
||||
echo "Below is a list of themes shipped with rofi." >>themes.md
|
||||
echo "Use \`rofi-theme-selector\` to select and use one of these themes." >>themes.md
|
||||
|
||||
Xvfb :1234 -screen 0 1920x1080x24 &
|
||||
XEPHYR_PID=$!
|
||||
export DISPLAY=:1234
|
||||
sleep 0.5;
|
||||
sleep 0.5
|
||||
run_theme "default"
|
||||
for theme in ${THEMES}
|
||||
do
|
||||
run_theme ${theme}
|
||||
for theme in ${THEMES}; do
|
||||
run_theme "${theme}"
|
||||
done
|
||||
kill ${XEPHYR_PID}
|
||||
|
105
source/helper.c
105
source/helper.c
@@ -54,6 +54,16 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const char *const MatchingMethodStr[MM_NUM_MATCHERS] = {
|
||||
"Normal", "Regex", "Glob", "Fuzzy", "Prefix"};
|
||||
|
||||
static int MatchingMethodEnabled[MM_NUM_MATCHERS] = {
|
||||
MM_NORMAL,
|
||||
-1,
|
||||
};
|
||||
static int NUMMatchingMethodEnabled = 1;
|
||||
static int CurrentMatchingMethod = 0;
|
||||
|
||||
/**
|
||||
* Textual description of positioning rofi.
|
||||
*/
|
||||
@@ -67,6 +77,23 @@ char **stored_argv = NULL;
|
||||
|
||||
char *helper_string_replace_if_exists_v(char *string, GHashTable *h);
|
||||
|
||||
const char *helper_get_matching_mode_str(void) {
|
||||
return MatchingMethodStr[config.matching_method];
|
||||
}
|
||||
void helper_select_next_matching_mode(void) {
|
||||
|
||||
CurrentMatchingMethod++;
|
||||
CurrentMatchingMethod %= NUMMatchingMethodEnabled;
|
||||
config.matching_method = MatchingMethodEnabled[CurrentMatchingMethod];
|
||||
}
|
||||
void helper_select_previous_matching_mode(void) {
|
||||
CurrentMatchingMethod--;
|
||||
if (CurrentMatchingMethod < 0) {
|
||||
CurrentMatchingMethod = NUMMatchingMethodEnabled - 1;
|
||||
}
|
||||
config.matching_method = MatchingMethodEnabled[CurrentMatchingMethod];
|
||||
}
|
||||
|
||||
void cmd_set_arguments(int argc, char **argv) {
|
||||
stored_argc = argc;
|
||||
stored_argv = argv;
|
||||
@@ -582,7 +609,7 @@ int create_pid_file(const char *pidfile, gboolean kill_running) {
|
||||
char buffer[64] = {
|
||||
0,
|
||||
};
|
||||
ssize_t l = read(fd, &buffer, 63);
|
||||
ssize_t l = read(fd, &(buffer[0]), 63);
|
||||
if (l > 1) {
|
||||
buffer[l] = 0;
|
||||
pid_t pid = g_ascii_strtoll(buffer, NULL, 0);
|
||||
@@ -664,26 +691,42 @@ int config_sanity_check(void) {
|
||||
}
|
||||
|
||||
if (config.matching) {
|
||||
if (g_strcmp0(config.matching, "regex") == 0) {
|
||||
config.matching_method = MM_REGEX;
|
||||
} else if (g_strcmp0(config.matching, "glob") == 0) {
|
||||
config.matching_method = MM_GLOB;
|
||||
} else if (g_strcmp0(config.matching, "fuzzy") == 0) {
|
||||
config.matching_method = MM_FUZZY;
|
||||
} else if (g_strcmp0(config.matching, "normal") == 0) {
|
||||
config.matching_method = MM_NORMAL;
|
||||
;
|
||||
} else if (g_strcmp0(config.matching, "prefix") == 0) {
|
||||
config.matching_method = MM_PREFIX;
|
||||
} else {
|
||||
char **strv = g_strsplit(config.matching, ",", 0);
|
||||
if (strv) {
|
||||
int matching_method_index = 0;
|
||||
for (char **str = strv; *str && matching_method_index < MM_NUM_MATCHERS;
|
||||
str++) {
|
||||
gboolean found = FALSE;
|
||||
for (unsigned i = 0;
|
||||
i < MM_NUM_MATCHERS && matching_method_index < MM_NUM_MATCHERS;
|
||||
i++) {
|
||||
if (g_ascii_strcasecmp(*str, MatchingMethodStr[i]) == 0) {
|
||||
MatchingMethodEnabled[matching_method_index] = i;
|
||||
matching_method_index++;
|
||||
NUMMatchingMethodEnabled = matching_method_index;
|
||||
if (matching_method_index == MM_NUM_MATCHERS) {
|
||||
found_error = 1;
|
||||
g_string_append_printf(msg,
|
||||
"\t<b>config.matching</b> = %s to many "
|
||||
"matching options enabled.\n",
|
||||
config.matching);
|
||||
}
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
g_string_append_printf(msg,
|
||||
"\t<b>config.matching</b>=%s is not a valid "
|
||||
"matching strategy.\nValid options are: glob, "
|
||||
"regex, fuzzy, prefix or normal.\n",
|
||||
config.matching);
|
||||
*str);
|
||||
found_error = 1;
|
||||
}
|
||||
}
|
||||
config.matching_method = MatchingMethodEnabled[0];
|
||||
g_strfreev(strv);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.element_height < 1) {
|
||||
g_string_append_printf(msg,
|
||||
@@ -769,7 +812,8 @@ char *rofi_expand_path(const char *input) {
|
||||
((a) < (b) ? ((a) < (c) ? (a) : (c)) : ((b) < (c) ? (b) : (c)))
|
||||
|
||||
unsigned int levenshtein(const char *needle, const glong needlelen,
|
||||
const char *haystack, const glong haystacklen) {
|
||||
const char *haystack, const glong haystacklen,
|
||||
int case_sensitive) {
|
||||
if (needlelen == G_MAXLONG) {
|
||||
// String to long, we cannot handle this.
|
||||
return UINT_MAX;
|
||||
@@ -785,12 +829,12 @@ unsigned int levenshtein(const char *needle, const glong needlelen,
|
||||
const char *needles = needle;
|
||||
column[0] = x;
|
||||
gunichar haystackc = g_utf8_get_char(haystack);
|
||||
if (!config.case_sensitive) {
|
||||
if (!case_sensitive) {
|
||||
haystackc = g_unichar_tolower(haystackc);
|
||||
}
|
||||
for (glong y = 1, lastdiag = x - 1; y <= needlelen; y++) {
|
||||
gunichar needlec = g_utf8_get_char(needles);
|
||||
if (!config.case_sensitive) {
|
||||
if (!case_sensitive) {
|
||||
needlec = g_unichar_tolower(needlec);
|
||||
}
|
||||
unsigned int olddiag = column[y];
|
||||
@@ -917,7 +961,7 @@ static int rofi_scorer_get_score_for(enum CharClass prev, enum CharClass curr) {
|
||||
}
|
||||
|
||||
int rofi_scorer_fuzzy_evaluate(const char *pattern, glong plen, const char *str,
|
||||
glong slen) {
|
||||
glong slen, int case_sensitive) {
|
||||
if (slen > FUZZY_SCORER_MAX_LENGTH) {
|
||||
return -MIN_SCORE;
|
||||
}
|
||||
@@ -952,8 +996,7 @@ int rofi_scorer_fuzzy_evaluate(const char *pattern, glong plen, const char *str,
|
||||
left = dp[si];
|
||||
lefts = MAX(lefts + GAP_SCORE, left);
|
||||
sc = g_utf8_get_char(sit);
|
||||
if (config.case_sensitive
|
||||
? pc == sc
|
||||
if (case_sensitive ? pc == sc
|
||||
: g_unichar_tolower(pc) == g_unichar_tolower(sc)) {
|
||||
int t = score[si] * (pstart ? PATTERN_START_MULTIPLIER
|
||||
: PATTERN_NON_START_MULTIPLIER);
|
||||
@@ -1248,6 +1291,28 @@ void parse_ranges(char *input, rofi_range_pair **list, unsigned int *length) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int parse_case_sensitivity(const char *input) {
|
||||
int case_sensitive = config.case_sensitive;
|
||||
if (config.case_smart) {
|
||||
// By default case is false, unless the search query has a
|
||||
// uppercase in it?
|
||||
case_sensitive = FALSE;
|
||||
const char *end;
|
||||
if (g_utf8_validate(input, -1, &end)) {
|
||||
for (const char *c = (input); !case_sensitive && c != NULL && *c;
|
||||
c = g_utf8_next_char(c)) {
|
||||
gunichar uc = g_utf8_get_char(c);
|
||||
if (g_unichar_isupper(uc)) {
|
||||
case_sensitive = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return case_sensitive;
|
||||
}
|
||||
|
||||
void rofi_output_formatted_line(const char *format, const char *string,
|
||||
int selected_line, const char *filter) {
|
||||
for (int i = 0; format && format[i]; i++) {
|
||||
|
@@ -332,6 +332,14 @@ ActionBindingEntry rofi_bindings[] = {
|
||||
.name = "kb-entry-history-down",
|
||||
.binding = "Control+Down",
|
||||
.comment = "Go down in the history of the entry box"},
|
||||
{.id = MATCHER_UP,
|
||||
.name = "kb-matcher-up",
|
||||
.binding = "Super+equal",
|
||||
.comment = "Switch to the previous matcher"},
|
||||
{.id = MATCHER_DOWN,
|
||||
.name = "kb-mather-down",
|
||||
.binding = "Super+minus",
|
||||
.comment = "Switch to the next matcher"},
|
||||
|
||||
/* Mouse-aware bindings */
|
||||
|
||||
|
@@ -159,6 +159,11 @@ const char *mode_get_name(const Mode *mode) {
|
||||
return mode->name;
|
||||
}
|
||||
|
||||
int mode_get_abi_version(Mode *const mode) {
|
||||
g_assert(mode != NULL);
|
||||
return mode->abi_version;
|
||||
}
|
||||
|
||||
void mode_free(Mode **mode) {
|
||||
g_assert(mode != NULL);
|
||||
g_assert((*mode) != NULL);
|
||||
@@ -245,4 +250,10 @@ gboolean mode_is_completer(const Mode *mode) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void mode_plugin_set_module(Mode *mode, GModule *mod){
|
||||
mode->module = mod;
|
||||
}
|
||||
GModule *mode_plugin_get_module(Mode *mode){
|
||||
return mode->module;
|
||||
}
|
||||
/**@}*/
|
||||
|
@@ -289,8 +289,8 @@ static gpointer read_input_thread(gpointer userdata) {
|
||||
if (FD_ISSET(fd, &rfds)) {
|
||||
ssize_t readbytes = 0;
|
||||
if ((nread + 1024) > len) {
|
||||
line = g_realloc(line, (nread + 1024));
|
||||
len = nread + 1024;
|
||||
line = g_realloc(line, (len + 2048));
|
||||
len = len + 2048;
|
||||
}
|
||||
readbytes = read(fd, &line[nread], 1023);
|
||||
if (readbytes > 0) {
|
||||
@@ -959,7 +959,8 @@ int dmenu_mode_dialog(void) {
|
||||
char *select = NULL;
|
||||
find_arg_str("-select", &select);
|
||||
if (select != NULL) {
|
||||
rofi_int_matcher **tokens = helper_tokenize(select, config.case_sensitive);
|
||||
rofi_int_matcher **tokens =
|
||||
helper_tokenize(select, parse_case_sensitivity(select));
|
||||
unsigned int i = 0;
|
||||
for (i = 0; i < cmd_list_length; i++) {
|
||||
if (helper_token_match(tokens, cmd_list[i].entry)) {
|
||||
@@ -970,8 +971,9 @@ int dmenu_mode_dialog(void) {
|
||||
helper_tokenize_free(tokens);
|
||||
}
|
||||
if (find_arg("-dump") >= 0) {
|
||||
rofi_int_matcher **tokens = helper_tokenize(
|
||||
config.filter ? config.filter : "", config.case_sensitive);
|
||||
char *filter = config.filter ? config.filter : "";
|
||||
rofi_int_matcher **tokens =
|
||||
helper_tokenize(filter, parse_case_sensitivity(filter));
|
||||
unsigned int i = 0;
|
||||
for (i = 0; i < cmd_list_length; i++) {
|
||||
if (tokens == NULL || helper_token_match(tokens, cmd_list[i].entry)) {
|
||||
|
@@ -353,7 +353,8 @@ static gboolean recursive_browser_async_read_proc(gint fd,
|
||||
}
|
||||
} else if (command == 'q') {
|
||||
if (pd->loading) {
|
||||
rofi_view_set_overlay(rofi_view_get_active(), NULL);
|
||||
// TODO: add enable.
|
||||
//rofi_view_set_overlay(rofi_view_get_active(), NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -350,6 +350,10 @@ static ModeMode script_mode_result(Mode *sw, int mretv, char **input,
|
||||
retv = (mretv & MENU_LOWER_MASK);
|
||||
return retv;
|
||||
}
|
||||
} else if ((mretv & MENU_ENTRY_DELETE) && selected_line != UINT32_MAX) {
|
||||
script_mode_reset_highlight(sw);
|
||||
new_list = execute_executor(sw, rmpd->cmd_list[selected_line].entry, &new_length,
|
||||
3, &(rmpd->cmd_list[selected_line]));
|
||||
} else if ((mretv & MENU_OK) && rmpd->cmd_list[selected_line].entry != NULL) {
|
||||
if (rmpd->cmd_list[selected_line].nonselectable) {
|
||||
return RELOAD_DIALOG;
|
||||
|
@@ -71,10 +71,6 @@
|
||||
|
||||
#include "timings.h"
|
||||
|
||||
// Plugin abi version.
|
||||
// TODO: move this check to mode.c
|
||||
#include "mode-private.h"
|
||||
|
||||
/** Location of pidfile for this instance. */
|
||||
char *pidfile = NULL;
|
||||
/** Location of Cache directory. */
|
||||
@@ -202,7 +198,7 @@ static void run_mode_index(ModeMode mode) {
|
||||
for (unsigned int i = 0; i < num_modes; i++) {
|
||||
if (!mode_init(modes[i])) {
|
||||
GString *str = g_string_new("Failed to initialize the mode: ");
|
||||
g_string_append(str, modes[i]->name);
|
||||
g_string_append(str, mode_get_name(modes[i]));
|
||||
g_string_append(str, "\n");
|
||||
|
||||
rofi_view_error_dialog(str->str, ERROR_MSG_MARKUP);
|
||||
@@ -303,7 +299,7 @@ static void print_list_of_modes(int is_term) {
|
||||
}
|
||||
printf(" • %s%s%s%s\n", active ? "+" : "",
|
||||
is_term ? (active ? color_green : color_red) : "",
|
||||
available_modes[i]->name, is_term ? color_reset : "");
|
||||
mode_get_name(available_modes[i]), is_term ? color_reset : "");
|
||||
}
|
||||
}
|
||||
static void print_main_application_options(int is_term) {
|
||||
@@ -475,7 +471,7 @@ static void help_print_mode_not_found(const char *mode) {
|
||||
}
|
||||
}
|
||||
g_string_append_printf(str, " * %s%s\n", active ? "+" : "",
|
||||
available_modes[i]->name);
|
||||
mode_get_name(available_modes[i]));
|
||||
}
|
||||
rofi_add_error_message(str);
|
||||
}
|
||||
@@ -489,7 +485,7 @@ static void help_print_no_arguments(void) {
|
||||
g_string_append(emesg, "The following modes are enabled:\n");
|
||||
for (unsigned int j = 0; j < num_modes; j++) {
|
||||
g_string_append_printf(emesg, " • <span color=\"green\">%s</span>\n",
|
||||
modes[j]->name);
|
||||
mode_get_name(modes[j]));
|
||||
}
|
||||
g_string_append(emesg, "\nThe following modes can be enabled:\n");
|
||||
for (unsigned int i = 0; i < num_available_modes; i++) {
|
||||
@@ -502,7 +498,7 @@ static void help_print_no_arguments(void) {
|
||||
}
|
||||
if (!active) {
|
||||
g_string_append_printf(emesg, " • <span color=\"red\">%s</span>\n",
|
||||
available_modes[i]->name);
|
||||
mode_get_name(available_modes[i]));
|
||||
}
|
||||
}
|
||||
g_string_append(emesg, "\nTo activate a mode, add it to the list in "
|
||||
@@ -565,7 +561,7 @@ static void cleanup(void) {
|
||||
|
||||
Mode *rofi_collect_modes_search(const char *name) {
|
||||
for (unsigned int i = 0; i < num_available_modes; i++) {
|
||||
if (g_strcmp0(name, available_modes[i]->name) == 0) {
|
||||
if (g_strcmp0(name, mode_get_name(available_modes[i])) == 0) {
|
||||
return available_modes[i];
|
||||
}
|
||||
}
|
||||
@@ -577,7 +573,7 @@ Mode *rofi_collect_modes_search(const char *name) {
|
||||
* @returns TRUE when success.
|
||||
*/
|
||||
static gboolean rofi_collectmodes_add(Mode *mode) {
|
||||
Mode *m = rofi_collect_modes_search(mode->name);
|
||||
Mode *m = rofi_collect_modes_search(mode_get_name(mode));
|
||||
if (m == NULL) {
|
||||
available_modes =
|
||||
g_realloc(available_modes, sizeof(Mode *) * (num_available_modes + 1));
|
||||
@@ -605,13 +601,13 @@ static void rofi_collectmodes_dir(const char *base_dir) {
|
||||
if (mod) {
|
||||
Mode *m = NULL;
|
||||
if (g_module_symbol(mod, "mode", (gpointer *)&m)) {
|
||||
if (m->abi_version != ABI_VERSION) {
|
||||
if (mode_get_abi_version(m) != ABI_VERSION) {
|
||||
g_warning("ABI version of plugin: '%s' does not match: %08X "
|
||||
"expecting: %08X",
|
||||
dn, m->abi_version, ABI_VERSION);
|
||||
dn, mode_get_abi_version(m), ABI_VERSION);
|
||||
g_module_close(mod);
|
||||
} else {
|
||||
m->module = mod;
|
||||
mode_plugin_set_module(m, mod);
|
||||
if (!rofi_collectmodes_add(m)) {
|
||||
g_module_close(mod);
|
||||
}
|
||||
@@ -684,8 +680,8 @@ static void rofi_collectmodes_setup(void) {
|
||||
}
|
||||
static void rofi_collectmodes_destroy(void) {
|
||||
for (unsigned int i = 0; i < num_available_modes; i++) {
|
||||
if (available_modes[i]->module) {
|
||||
GModule *mod = available_modes[i]->module;
|
||||
if (mode_plugin_get_module(available_modes[i])) {
|
||||
GModule *mod = mode_plugin_get_module(available_modes[i]);
|
||||
available_modes[i] = NULL;
|
||||
g_module_close(mod);
|
||||
}
|
||||
@@ -1107,7 +1103,9 @@ int main(int argc, char *argv[]) {
|
||||
extern const char *rasi_theme_file_extensions[];
|
||||
char *file2 =
|
||||
helper_get_theme_path(config_path, rasi_theme_file_extensions, NULL);
|
||||
char *filename = rofi_theme_parse_prepare_file(file2);
|
||||
GFile *gf = g_file_new_for_path(file2);
|
||||
char *filename = g_file_get_path(gf);
|
||||
g_object_unref(gf);
|
||||
g_free(file2);
|
||||
if (filename && g_file_test(filename, G_FILE_TEST_EXISTS)) {
|
||||
if (rofi_theme_parse_file(filename)) {
|
||||
|
176
source/view.c
176
source/view.c
@@ -81,14 +81,15 @@ struct _rofi_view_cache_state CacheState = {
|
||||
.max_refilter_time = 0.0,
|
||||
.delayed_mode = FALSE,
|
||||
.user_timeout = 0,
|
||||
.overlay_timeout = 0,
|
||||
.entry_history_enable = TRUE,
|
||||
.entry_history = NULL,
|
||||
.entry_history_length = 0,
|
||||
.entry_history_index = 0,
|
||||
};
|
||||
|
||||
static char *get_matching_state(void) {
|
||||
if (config.case_sensitive) {
|
||||
static char *get_matching_state(RofiViewState* state) {
|
||||
if (state->case_sensitive) {
|
||||
if (config.sort) {
|
||||
return "±";
|
||||
} else {
|
||||
@@ -113,6 +114,18 @@ static int lev_sort(const void *p1, const void *p2, void *arg) {
|
||||
return distances[*a] - distances[*b];
|
||||
}
|
||||
|
||||
static void screenshot_taken_user_callback(const char *path) {
|
||||
if (config.on_screenshot_taken == NULL)
|
||||
return;
|
||||
|
||||
char **args = NULL;
|
||||
int argv = 0;
|
||||
helper_parse_setup(config.on_screenshot_taken, &args, &argv, "{path}", path,
|
||||
(char *)0);
|
||||
if (args != NULL)
|
||||
helper_execute(NULL, args, "", config.on_screenshot_taken, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a screenshot of Rofi at that point in time.
|
||||
*/
|
||||
@@ -172,6 +185,7 @@ void rofi_capture_screenshot(void) {
|
||||
g_warning("Failed to produce screenshot '%s', got error: '%s'", fpath,
|
||||
cairo_status_to_string(status));
|
||||
}
|
||||
screenshot_taken_user_callback(fpath);
|
||||
}
|
||||
cairo_destroy(draw);
|
||||
}
|
||||
@@ -444,12 +458,13 @@ static void filter_elements(thread_state *ts,
|
||||
glong slen = g_utf8_strlen(str, -1);
|
||||
switch (config.sorting_method_enum) {
|
||||
case SORT_FZF:
|
||||
t->state->distance[i] =
|
||||
rofi_scorer_fuzzy_evaluate(t->pattern, t->plen, str, slen);
|
||||
t->state->distance[i] = rofi_scorer_fuzzy_evaluate(
|
||||
t->pattern, t->plen, str, slen, t->state->case_sensitive);
|
||||
break;
|
||||
case SORT_NORMAL:
|
||||
default:
|
||||
t->state->distance[i] = levenshtein(t->pattern, t->plen, str, slen);
|
||||
t->state->distance[i] = levenshtein(t->pattern, t->plen, str, slen,
|
||||
t->state->case_sensitive);
|
||||
break;
|
||||
}
|
||||
g_free(str);
|
||||
@@ -620,9 +635,31 @@ inline static void rofi_view_nav_last(RofiViewState *state) {
|
||||
// state->selected = state->filtered_lines - 1;
|
||||
listview_set_selected(state->list_view, -1);
|
||||
}
|
||||
static void selection_changed_user_callback(unsigned int index,
|
||||
RofiViewState *state) {
|
||||
if (config.on_selection_changed == NULL)
|
||||
return;
|
||||
|
||||
int fstate = 0;
|
||||
char *text = mode_get_display_value(state->sw, state->line_map[index],
|
||||
&fstate, NULL, TRUE);
|
||||
char **args = NULL;
|
||||
int argv = 0;
|
||||
helper_parse_setup(config.on_selection_changed, &args, &argv, "{entry}", text,
|
||||
(char *)0);
|
||||
if (args != NULL)
|
||||
helper_execute(NULL, args, "", config.on_selection_changed, NULL);
|
||||
g_free(text);
|
||||
}
|
||||
static void selection_changed_callback(G_GNUC_UNUSED listview *lv,
|
||||
unsigned int index, void *udata) {
|
||||
RofiViewState *state = (RofiViewState *)udata;
|
||||
if (index < state->filtered_lines) {
|
||||
if (state->previous_line != state->line_map[index]) {
|
||||
selection_changed_user_callback(index, state);
|
||||
state->previous_line = state->line_map[index];
|
||||
}
|
||||
}
|
||||
if (state->tb_current_entry) {
|
||||
if (index < state->filtered_lines) {
|
||||
int fstate = 0;
|
||||
@@ -630,7 +667,6 @@ static void selection_changed_callback(G_GNUC_UNUSED listview *lv,
|
||||
&fstate, NULL, TRUE);
|
||||
textbox_text(state->tb_current_entry, text);
|
||||
g_free(text);
|
||||
|
||||
} else {
|
||||
textbox_text(state->tb_current_entry, "");
|
||||
}
|
||||
@@ -742,7 +778,12 @@ static gboolean rofi_view_refilter_real(RofiViewState *state) {
|
||||
unsigned int j = 0;
|
||||
gchar *pattern = mode_preprocess_input(state->sw, state->text->text);
|
||||
glong plen = pattern ? g_utf8_strlen(pattern, -1) : 0;
|
||||
state->tokens = helper_tokenize(pattern, config.case_sensitive);
|
||||
state->case_sensitive = parse_case_sensitivity(state->text->text);
|
||||
state->tokens = helper_tokenize(pattern, state->case_sensitive);
|
||||
|
||||
if (config.case_smart && state->case_indicator) {
|
||||
textbox_text(state->case_indicator, get_matching_state(state));
|
||||
}
|
||||
/**
|
||||
* On long lists it can be beneficial to parallelize.
|
||||
* If number of threads is 1, no thread is spawn.
|
||||
@@ -1008,7 +1049,7 @@ static void rofi_view_trigger_global_action(KeyBindingAction action) {
|
||||
if (state->case_indicator != NULL) {
|
||||
config.sort = !config.sort;
|
||||
state->refilter = TRUE;
|
||||
textbox_text(state->case_indicator, get_matching_state());
|
||||
textbox_text(state->case_indicator, get_matching_state(state));
|
||||
}
|
||||
break;
|
||||
case MODE_PREVIOUS:
|
||||
@@ -1038,7 +1079,7 @@ static void rofi_view_trigger_global_action(KeyBindingAction action) {
|
||||
config.case_sensitive = !config.case_sensitive;
|
||||
(state->selected_line) = 0;
|
||||
state->refilter = TRUE;
|
||||
textbox_text(state->case_indicator, get_matching_state());
|
||||
textbox_text(state->case_indicator, get_matching_state(state));
|
||||
}
|
||||
break;
|
||||
// Special delete entry command.
|
||||
@@ -1214,7 +1255,6 @@ static void rofi_view_trigger_global_action(KeyBindingAction action) {
|
||||
// Nothing entered and nothing selected.
|
||||
state->retv = MENU_CUSTOM_INPUT;
|
||||
}
|
||||
|
||||
state->quit = TRUE;
|
||||
break;
|
||||
}
|
||||
@@ -1273,6 +1313,16 @@ static void rofi_view_trigger_global_action(KeyBindingAction action) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MATCHER_UP:
|
||||
helper_select_next_matching_mode();
|
||||
rofi_view_refilter(state);
|
||||
rofi_view_set_overlay_timeout(state, helper_get_matching_mode_str());
|
||||
break;
|
||||
case MATCHER_DOWN:
|
||||
helper_select_previous_matching_mode();
|
||||
rofi_view_refilter(state);
|
||||
rofi_view_set_overlay_timeout(state, helper_get_matching_mode_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1410,6 +1460,62 @@ void rofi_view_handle_mouse_motion(RofiViewState *state, gint x, gint y,
|
||||
}
|
||||
}
|
||||
|
||||
static void rofi_quit_user_callback(RofiViewState *state) {
|
||||
if (state->retv & MENU_OK) {
|
||||
if (config.on_entry_accepted == NULL)
|
||||
return;
|
||||
int fstate = 0;
|
||||
unsigned int selected = listview_get_selected(state->list_view);
|
||||
// TODO: handle custom text
|
||||
if (selected >= state->filtered_lines)
|
||||
return;
|
||||
// Pass selected text to custom command
|
||||
char *text = mode_get_display_value(state->sw, state->line_map[selected],
|
||||
&fstate, NULL, TRUE);
|
||||
char **args = NULL;
|
||||
int argv = 0;
|
||||
helper_parse_setup(config.on_entry_accepted, &args, &argv, "{entry}", text,
|
||||
(char *)0);
|
||||
if (args != NULL)
|
||||
helper_execute(NULL, args, "", config.on_entry_accepted, NULL);
|
||||
g_free(text);
|
||||
} else if (state->retv & MENU_CANCEL) {
|
||||
if (config.on_menu_canceled == NULL)
|
||||
return;
|
||||
helper_execute_command(NULL, config.on_menu_canceled, FALSE, NULL);
|
||||
} else if (state->retv & MENU_NEXT || state->retv & MENU_PREVIOUS ||
|
||||
state->retv & MENU_QUICK_SWITCH || state->retv & MENU_COMPLETE) {
|
||||
if (config.on_mode_changed == NULL)
|
||||
return;
|
||||
// TODO: pass mode name to custom command
|
||||
helper_execute_command(NULL, config.on_mode_changed, FALSE, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void rofi_view_maybe_update(RofiViewState *state) {
|
||||
if (rofi_view_get_completed(state)) {
|
||||
// Exec custom user commands
|
||||
rofi_quit_user_callback(state);
|
||||
// This menu is done.
|
||||
rofi_view_finalize(state);
|
||||
// If there a state. (for example error) reload it.
|
||||
state = rofi_view_get_active();
|
||||
|
||||
// cleanup, if no more state to display.
|
||||
if (state == NULL) {
|
||||
// Quit main-loop.
|
||||
rofi_quit_main_loop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Update if requested.
|
||||
if (state->refilter) {
|
||||
rofi_view_refilter(state);
|
||||
}
|
||||
rofi_view_update(state, TRUE);
|
||||
return;
|
||||
}
|
||||
WidgetTriggerActionResult textbox_button_trigger_action(
|
||||
widget *wid, MouseBindingMouseDefaultAction action, G_GNUC_UNUSED gint x,
|
||||
G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data) {
|
||||
@@ -1558,7 +1664,7 @@ static void rofi_view_add_widget(RofiViewState *state, widget *parent_widget,
|
||||
TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "*", 0, 0);
|
||||
// Add small separator between case indicator and text box.
|
||||
box_add((box *)parent_widget, WIDGET(state->case_indicator), FALSE);
|
||||
textbox_text(state->case_indicator, get_matching_state());
|
||||
textbox_text(state->case_indicator, get_matching_state(state));
|
||||
}
|
||||
/**
|
||||
* ENTRY BOX
|
||||
@@ -1694,6 +1800,7 @@ RofiViewState *rofi_view_create(Mode *sw, const char *input,
|
||||
state->menu_flags = menu_flags;
|
||||
state->sw = sw;
|
||||
state->selected_line = UINT32_MAX;
|
||||
state->previous_line = UINT32_MAX;
|
||||
state->retv = MENU_CANCEL;
|
||||
state->distance = NULL;
|
||||
state->quit = FALSE;
|
||||
@@ -1793,6 +1900,18 @@ RofiViewState *rofi_view_create(Mode *sw, const char *input,
|
||||
return state;
|
||||
}
|
||||
|
||||
static void rofi_error_user_callback(const char *msg) {
|
||||
if (config.on_menu_error == NULL)
|
||||
return;
|
||||
|
||||
char **args = NULL;
|
||||
int argv = 0;
|
||||
helper_parse_setup(config.on_menu_error, &args, &argv, "{error}", msg,
|
||||
(char *)0);
|
||||
if (args != NULL)
|
||||
helper_execute(NULL, args, "", config.on_menu_error, NULL);
|
||||
}
|
||||
|
||||
int rofi_view_error_dialog(const char *msg, int markup) {
|
||||
RofiViewState *state = __rofi_view_state_create();
|
||||
state->retv = MENU_CANCEL;
|
||||
@@ -1836,6 +1955,9 @@ int rofi_view_error_dialog(const char *msg, int markup) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Exec custom command
|
||||
rofi_error_user_callback(msg);
|
||||
|
||||
// Set it as current window.
|
||||
rofi_view_set_active(state);
|
||||
return TRUE;
|
||||
@@ -1905,10 +2027,38 @@ void rofi_view_workers_finalize(void) {
|
||||
}
|
||||
Mode *rofi_view_get_mode(RofiViewState *state) { return state->sw; }
|
||||
|
||||
static gboolean rofi_view_overlay_timeout(G_GNUC_UNUSED gpointer user_data) {
|
||||
RofiViewState *state = rofi_view_get_active();
|
||||
if (state) {
|
||||
widget_disable(WIDGET(state->overlay));
|
||||
}
|
||||
CacheState.overlay_timeout = 0;
|
||||
rofi_view_queue_redraw();
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
void rofi_view_set_overlay_timeout(RofiViewState *state, const char *text) {
|
||||
if (state->overlay == NULL || state->list_view == NULL) {
|
||||
return;
|
||||
}
|
||||
if (text == NULL) {
|
||||
widget_disable(WIDGET(state->overlay));
|
||||
return;
|
||||
}
|
||||
rofi_view_set_overlay(state, text);
|
||||
int timeout = rofi_theme_get_integer(WIDGET(state->overlay), "timeout", 3);
|
||||
CacheState.overlay_timeout =
|
||||
g_timeout_add_seconds(timeout, rofi_view_overlay_timeout, state);
|
||||
}
|
||||
|
||||
void rofi_view_set_overlay(RofiViewState *state, const char *text) {
|
||||
if (state->overlay == NULL || state->list_view == NULL) {
|
||||
return;
|
||||
}
|
||||
if (CacheState.overlay_timeout > 0) {
|
||||
g_source_remove(CacheState.overlay_timeout);
|
||||
CacheState.overlay_timeout = 0;
|
||||
}
|
||||
if (text == NULL) {
|
||||
widget_disable(WIDGET(state->overlay));
|
||||
return;
|
||||
@@ -1965,10 +2115,6 @@ void rofi_view_update(RofiViewState *state, gboolean qr) {
|
||||
proxy->update(state, qr);
|
||||
}
|
||||
|
||||
void rofi_view_maybe_update(RofiViewState *state) {
|
||||
proxy->maybe_update(state);
|
||||
}
|
||||
|
||||
void rofi_view_temp_configure_notify(RofiViewState *state,
|
||||
xcb_configure_notify_event_t *xce) {
|
||||
proxy->temp_configure_notify(state, xce);
|
||||
|
@@ -64,8 +64,6 @@
|
||||
*/
|
||||
static void wayland_rofi_view_update(RofiViewState *state, gboolean qr);
|
||||
|
||||
static void wayland_rofi_view_maybe_update(RofiViewState *state);
|
||||
|
||||
/**
|
||||
* Structure holding some state
|
||||
*/
|
||||
@@ -119,7 +117,7 @@ static gboolean wayland_rofi_view_repaint(G_GNUC_UNUSED void *data) {
|
||||
// Repaint the view (if needed).
|
||||
// After a resize the edit_pixmap surface might not contain anything
|
||||
// anymore. If we already re-painted, this does nothing.
|
||||
wayland_rofi_view_maybe_update(state);
|
||||
rofi_view_maybe_update(state);
|
||||
WlState.repaint_source = 0;
|
||||
}
|
||||
return G_SOURCE_REMOVE;
|
||||
@@ -191,7 +189,7 @@ static gboolean wayland_rofi_view_reload_idle(G_GNUC_UNUSED gpointer data) {
|
||||
state->reload = TRUE;
|
||||
state->refilter = TRUE;
|
||||
|
||||
wayland_rofi_view_maybe_update(state);
|
||||
rofi_view_maybe_update(state);
|
||||
}
|
||||
WlState.idle_timeout = 0;
|
||||
return G_SOURCE_REMOVE;
|
||||
@@ -369,29 +367,6 @@ static void wayland_rofi_view_update(RofiViewState *state, gboolean qr) {
|
||||
*/
|
||||
void process_result(RofiViewState *state);
|
||||
|
||||
static void wayland_rofi_view_maybe_update(RofiViewState *state) {
|
||||
if (rofi_view_get_completed(state)) {
|
||||
// This menu is done.
|
||||
rofi_view_finalize(state);
|
||||
// If there a state. (for example error) reload it.
|
||||
state = rofi_view_get_active();
|
||||
|
||||
// cleanup, if no more state to display.
|
||||
if (state == NULL) {
|
||||
// Quit main-loop.
|
||||
rofi_quit_main_loop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Update if requested.
|
||||
if (state->refilter) {
|
||||
rofi_view_refilter(state);
|
||||
}
|
||||
wayland_rofi_view_update(state, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
static void wayland_rofi_view_frame_callback(void) {
|
||||
if (WlState.repaint_source == 0) {
|
||||
WlState.repaint_source = g_idle_add_full(
|
||||
@@ -427,14 +402,18 @@ static void wayland_rofi_view_cleanup(void) {
|
||||
g_source_remove(WlState.idle_timeout);
|
||||
WlState.idle_timeout = 0;
|
||||
}
|
||||
if (CacheState.user_timeout > 0) {
|
||||
g_source_remove(CacheState.user_timeout);
|
||||
CacheState.user_timeout = 0;
|
||||
}
|
||||
if (CacheState.refilter_timeout > 0) {
|
||||
g_source_remove(CacheState.refilter_timeout);
|
||||
CacheState.refilter_timeout = 0;
|
||||
}
|
||||
if (CacheState.overlay_timeout) {
|
||||
g_source_remove(CacheState.overlay_timeout);
|
||||
CacheState.overlay_timeout = 0;
|
||||
}
|
||||
if (CacheState.user_timeout > 0) {
|
||||
g_source_remove(CacheState.user_timeout);
|
||||
CacheState.user_timeout = 0;
|
||||
}
|
||||
if (WlState.repaint_source > 0) {
|
||||
g_source_remove(WlState.repaint_source);
|
||||
WlState.repaint_source = 0;
|
||||
@@ -458,7 +437,6 @@ static void wayland_rofi_view_pool_refresh(void) {
|
||||
|
||||
static view_proxy view_ = {
|
||||
.update = wayland_rofi_view_update,
|
||||
.maybe_update = wayland_rofi_view_maybe_update,
|
||||
.temp_configure_notify = NULL,
|
||||
.temp_click_to_exit = NULL,
|
||||
.frame_callback = wayland_rofi_view_frame_callback,
|
||||
|
@@ -250,6 +250,15 @@ textbox *textbox_create(widget *parent, WidgetType type, const char *name,
|
||||
tb->placeholder = g_markup_escape_text(placeholder, -1);
|
||||
}
|
||||
}
|
||||
|
||||
const char *password_mask_char =
|
||||
rofi_theme_get_string(WIDGET(tb), "password-mask", NULL);
|
||||
if (password_mask_char == NULL || (*password_mask_char) == '\0') {
|
||||
tb->password_mask_char = "*";
|
||||
} else {
|
||||
tb->password_mask_char = password_mask_char;
|
||||
}
|
||||
|
||||
textbox_text(tb, txt ? txt : "");
|
||||
textbox_cursor_end(tb);
|
||||
|
||||
@@ -336,11 +345,14 @@ static void __textbox_update_pango_text(textbox *tb) {
|
||||
}
|
||||
tb->show_placeholder = FALSE;
|
||||
if ((tb->flags & TB_PASSWORD) == TB_PASSWORD) {
|
||||
size_t l = g_utf8_strlen(tb->text, -1);
|
||||
char string[l + 1];
|
||||
memset(string, '*', l);
|
||||
string[l] = '\0';
|
||||
pango_layout_set_text(tb->layout, string, l);
|
||||
size_t text_len = g_utf8_strlen(tb->text, -1);
|
||||
size_t mask_len = strlen(tb->password_mask_char);
|
||||
char string[text_len * mask_len + 1];
|
||||
for (size_t offset = 0; offset < text_len * mask_len; offset += mask_len) {
|
||||
memcpy(string + offset, tb->password_mask_char, mask_len);
|
||||
}
|
||||
string[text_len * mask_len] = '\0';
|
||||
pango_layout_set_text(tb->layout, string, -1);
|
||||
} else if (tb->flags & TB_MARKUP || tb->tbft & MARKUP) {
|
||||
pango_layout_set_markup(tb->layout, tb->text, -1);
|
||||
} else {
|
||||
@@ -488,7 +500,6 @@ static void textbox_draw(widget *wid, cairo_t *draw) {
|
||||
return;
|
||||
}
|
||||
textbox *tb = (textbox *)wid;
|
||||
int dot_offset = 0;
|
||||
|
||||
if (tb->changed) {
|
||||
__textbox_update_pango_text(tb);
|
||||
@@ -521,7 +532,7 @@ static void textbox_draw(widget *wid, cairo_t *draw) {
|
||||
{
|
||||
int rem =
|
||||
MAX(0, tb->widget.w - widget_padding_get_padding_width(WIDGET(tb)) -
|
||||
line_width - dot_offset);
|
||||
line_width);
|
||||
switch (pango_layout_get_alignment(tb->layout)) {
|
||||
case PANGO_ALIGN_CENTER:
|
||||
x = rem * (tb->xalign - 0.5);
|
||||
@@ -530,7 +541,7 @@ static void textbox_draw(widget *wid, cairo_t *draw) {
|
||||
x = rem * (tb->xalign - 1.0);
|
||||
break;
|
||||
default:
|
||||
x = rem * tb->xalign + dot_offset;
|
||||
x = rem * tb->xalign;
|
||||
break;
|
||||
}
|
||||
x += widget_padding_get_left(WIDGET(tb));
|
||||
@@ -541,11 +552,20 @@ static void textbox_draw(widget *wid, cairo_t *draw) {
|
||||
// We want to place the cursor based on the text shown.
|
||||
const char *text = pango_layout_get_text(tb->layout);
|
||||
// Clamp the position, should not be needed, but we are paranoid.
|
||||
int cursor_offset = MIN(tb->cursor, g_utf8_strlen(text, -1));
|
||||
PangoRectangle pos;
|
||||
size_t cursor_offset;
|
||||
|
||||
if ((tb->flags & TB_PASSWORD) == TB_PASSWORD) {
|
||||
// Calculate cursor position based on mask length
|
||||
size_t mask_len = strlen(tb->password_mask_char);
|
||||
cursor_offset = MIN(tb->cursor * mask_len, strlen(text));
|
||||
} else {
|
||||
cursor_offset = MIN(tb->cursor, g_utf8_strlen(text, -1));
|
||||
// convert to byte location.
|
||||
char *offset = g_utf8_offset_to_pointer(text, cursor_offset);
|
||||
pango_layout_get_cursor_pos(tb->layout, offset - text, &pos, NULL);
|
||||
cursor_offset = offset - text;
|
||||
}
|
||||
PangoRectangle pos;
|
||||
pango_layout_get_cursor_pos(tb->layout, cursor_offset, &pos, NULL);
|
||||
int cursor_x = pos.x / PANGO_SCALE;
|
||||
int cursor_y = pos.y / PANGO_SCALE;
|
||||
int cursor_height = pos.height / PANGO_SCALE;
|
||||
|
@@ -310,28 +310,6 @@ static void xcb_rofi_view_update(RofiViewState *state, gboolean qr) {
|
||||
}
|
||||
}
|
||||
|
||||
static void xcb_rofi_view_maybe_update(RofiViewState *state) {
|
||||
if (rofi_view_get_completed(state)) {
|
||||
// This menu is done.
|
||||
rofi_view_finalize(state);
|
||||
// If there a state. (for example error) reload it.
|
||||
state = rofi_view_get_active();
|
||||
|
||||
// cleanup, if no more state to display.
|
||||
if (state == NULL) {
|
||||
// Quit main-loop.
|
||||
rofi_quit_main_loop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Update if requested.
|
||||
if (state->refilter) {
|
||||
rofi_view_refilter(state);
|
||||
}
|
||||
rofi_view_update(state, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the window position
|
||||
@@ -962,14 +940,18 @@ static void xcb_rofi_view_cleanup(void) {
|
||||
g_source_remove(XcbState.idle_timeout);
|
||||
XcbState.idle_timeout = 0;
|
||||
}
|
||||
if (CacheState.user_timeout > 0) {
|
||||
g_source_remove(CacheState.user_timeout);
|
||||
CacheState.user_timeout = 0;
|
||||
}
|
||||
if (CacheState.refilter_timeout > 0) {
|
||||
g_source_remove(CacheState.refilter_timeout);
|
||||
CacheState.refilter_timeout = 0;
|
||||
}
|
||||
if (CacheState.overlay_timeout) {
|
||||
g_source_remove(CacheState.overlay_timeout);
|
||||
CacheState.overlay_timeout = 0;
|
||||
}
|
||||
if (CacheState.user_timeout > 0) {
|
||||
g_source_remove(CacheState.user_timeout);
|
||||
CacheState.user_timeout = 0;
|
||||
}
|
||||
if (XcbState.repaint_source > 0) {
|
||||
g_source_remove(XcbState.repaint_source);
|
||||
XcbState.repaint_source = 0;
|
||||
@@ -1020,7 +1002,6 @@ static void xcb_rofi_view_set_window_title(const char *title) {
|
||||
|
||||
static view_proxy view_ = {
|
||||
.update = xcb_rofi_view_update,
|
||||
.maybe_update = xcb_rofi_view_maybe_update,
|
||||
.temp_configure_notify = xcb_rofi_view_temp_configure_notify,
|
||||
.temp_click_to_exit = xcb_rofi_view_temp_click_to_exit,
|
||||
.frame_callback = xcb_rofi_view_frame_callback,
|
||||
|
@@ -132,6 +132,43 @@ static XrmOption xrmOptions[] = {
|
||||
"Custom command to generate preview icons",
|
||||
CONFIG_DEFAULT},
|
||||
|
||||
{xrm_String,
|
||||
"on-selection-changed",
|
||||
{.str = &config.on_selection_changed},
|
||||
NULL,
|
||||
"Custom command to call when menu selection changes",
|
||||
CONFIG_DEFAULT},
|
||||
{xrm_String,
|
||||
"on-mode-changed",
|
||||
{.str = &config.on_mode_changed},
|
||||
NULL,
|
||||
"Custom command to call when menu mode changes",
|
||||
CONFIG_DEFAULT},
|
||||
{xrm_String,
|
||||
"on-entry-accepted",
|
||||
{.str = &config.on_entry_accepted},
|
||||
NULL,
|
||||
"Custom command to call when menu entry is accepted",
|
||||
CONFIG_DEFAULT},
|
||||
{xrm_String,
|
||||
"on-menu-canceled",
|
||||
{.str = &config.on_menu_canceled},
|
||||
NULL,
|
||||
"Custom command to call when menu is canceled",
|
||||
CONFIG_DEFAULT},
|
||||
{xrm_String,
|
||||
"on-menu-error",
|
||||
{.str = &config.on_menu_error},
|
||||
NULL,
|
||||
"Custom command to call when menu finds errors",
|
||||
CONFIG_DEFAULT},
|
||||
{xrm_String,
|
||||
"on-screenshot-taken",
|
||||
{.str = &config.on_screenshot_taken},
|
||||
NULL,
|
||||
"Custom command to call when menu screenshot is taken",
|
||||
CONFIG_DEFAULT},
|
||||
|
||||
{xrm_String,
|
||||
"terminal",
|
||||
{.str = &config.terminal_emulator},
|
||||
@@ -249,6 +286,12 @@ static XrmOption xrmOptions[] = {
|
||||
NULL,
|
||||
"Set case-sensitivity",
|
||||
CONFIG_DEFAULT},
|
||||
{xrm_Boolean,
|
||||
"case-smart",
|
||||
{.num = &config.case_smart},
|
||||
NULL,
|
||||
"Set smartcase like vim (determine case-sensitivity by input)",
|
||||
CONFIG_DEFAULT},
|
||||
{xrm_Boolean,
|
||||
"cycle",
|
||||
{.num = &config.cycle},
|
||||
|
Submodule subprojects/libnkutils updated: 72bd7fb07f...2f220a40ad
@@ -139,25 +139,25 @@ int main(int argc, char **argv) {
|
||||
*/
|
||||
|
||||
TASSERT(levenshtein("aap", g_utf8_strlen("aap", -1), "aap",
|
||||
g_utf8_strlen("aap", -1)) == 0);
|
||||
g_utf8_strlen("aap", -1), 0) == 0);
|
||||
TASSERT(levenshtein("aap", g_utf8_strlen("aap", -1), "aap ",
|
||||
g_utf8_strlen("aap ", -1)) == 1);
|
||||
g_utf8_strlen("aap ", -1), 0) == 1);
|
||||
TASSERT(levenshtein("aap ", g_utf8_strlen("aap ", -1), "aap",
|
||||
g_utf8_strlen("aap", -1)) == 1);
|
||||
g_utf8_strlen("aap", -1), 0) == 1);
|
||||
TASSERTE(levenshtein("aap", g_utf8_strlen("aap", -1), "aap noot",
|
||||
g_utf8_strlen("aap noot", -1)),
|
||||
g_utf8_strlen("aap noot", -1), 0),
|
||||
5u);
|
||||
TASSERTE(levenshtein("aap", g_utf8_strlen("aap", -1), "noot aap",
|
||||
g_utf8_strlen("noot aap", -1)),
|
||||
g_utf8_strlen("noot aap", -1), 0),
|
||||
5u);
|
||||
TASSERTE(levenshtein("aap", g_utf8_strlen("aap", -1), "noot aap mies",
|
||||
g_utf8_strlen("noot aap mies", -1)),
|
||||
g_utf8_strlen("noot aap mies", -1), 0),
|
||||
10u);
|
||||
TASSERTE(levenshtein("noot aap mies", g_utf8_strlen("noot aap mies", -1),
|
||||
"aap", g_utf8_strlen("aap", -1)),
|
||||
"aap", g_utf8_strlen("aap", -1), 0),
|
||||
10u);
|
||||
TASSERTE(levenshtein("otp", g_utf8_strlen("otp", -1), "noot aap",
|
||||
g_utf8_strlen("noot aap", -1)),
|
||||
g_utf8_strlen("noot aap", -1), 0),
|
||||
5u);
|
||||
/**
|
||||
* Quick converision check.
|
||||
@@ -189,20 +189,48 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
{
|
||||
TASSERTL(
|
||||
rofi_scorer_fuzzy_evaluate("aap noot mies", 12, "aap noot mies", 12),
|
||||
rofi_scorer_fuzzy_evaluate("aap noot mies", 12, "aap noot mies", 12, 0),
|
||||
-605);
|
||||
TASSERTL(rofi_scorer_fuzzy_evaluate("anm", 3, "aap noot mies", 12), -155);
|
||||
TASSERTL(rofi_scorer_fuzzy_evaluate("blu", 3, "aap noot mies", 12),
|
||||
TASSERTL(rofi_scorer_fuzzy_evaluate("anm", 3, "aap noot mies", 12, 0),
|
||||
-155);
|
||||
TASSERTL(rofi_scorer_fuzzy_evaluate("blu", 3, "aap noot mies", 12, 0),
|
||||
1073741824);
|
||||
config.case_sensitive = TRUE;
|
||||
TASSERTL(rofi_scorer_fuzzy_evaluate("Anm", 3, "aap noot mies", 12),
|
||||
TASSERTL(rofi_scorer_fuzzy_evaluate("Anm", 3, "aap noot mies", 12, 1),
|
||||
1073741754);
|
||||
config.case_sensitive = FALSE;
|
||||
TASSERTL(rofi_scorer_fuzzy_evaluate("Anm", 3, "aap noot mies", 12), -155);
|
||||
TASSERTL(rofi_scorer_fuzzy_evaluate("aap noot mies", 12, "Anm", 3),
|
||||
TASSERTL(rofi_scorer_fuzzy_evaluate("Anm", 3, "aap noot mies", 12, 0),
|
||||
-155);
|
||||
TASSERTL(rofi_scorer_fuzzy_evaluate("aap noot mies", 12, "Anm", 3, 0),
|
||||
1073741824);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case sensitivity
|
||||
*/
|
||||
{
|
||||
int case_smart = config.case_smart;
|
||||
int case_sensitive = config.case_sensitive;
|
||||
{
|
||||
config.case_smart = FALSE;
|
||||
config.case_sensitive = FALSE;
|
||||
TASSERT(parse_case_sensitivity("all lower case 你好") == 0);
|
||||
TASSERT(parse_case_sensitivity("not All lowEr Case 你好") == 0);
|
||||
config.case_sensitive = TRUE;
|
||||
TASSERT(parse_case_sensitivity("all lower case 你好") == 1);
|
||||
TASSERT(parse_case_sensitivity("not All lowEr Case 你好") == 1);
|
||||
}
|
||||
{
|
||||
config.case_smart = TRUE;
|
||||
config.case_sensitive = TRUE;
|
||||
TASSERT(parse_case_sensitivity("all lower case") == 0);
|
||||
TASSERT(parse_case_sensitivity("AAAAAAAAAAAA") == 1);
|
||||
config.case_sensitive = FALSE;
|
||||
TASSERT(parse_case_sensitivity("all lower case 你好") == 0);
|
||||
TASSERT(parse_case_sensitivity("not All lowEr Case 你好") == 1);
|
||||
}
|
||||
config.case_smart = case_smart;
|
||||
config.case_sensitive = case_sensitive;
|
||||
}
|
||||
|
||||
char *a;
|
||||
a = helper_string_replace_if_exists(
|
||||
"{terminal} [-t {title} blub ]-e {cmd}", "{cmd}", "aap", "{title}",
|
||||
|
@@ -125,7 +125,7 @@ END_TEST
|
||||
|
||||
START_TEST(test_mode_num_items) {
|
||||
unsigned int rows = mode_get_num_entries(&help_keys_mode);
|
||||
ck_assert_int_eq(rows, 79);
|
||||
ck_assert_int_eq(rows, 81);
|
||||
for (unsigned int i = 0; i < rows; i++) {
|
||||
int state = 0;
|
||||
GList *list = NULL;
|
||||
|
Reference in New Issue
Block a user