Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added calculator functionnality #217

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install build-essential llvm clang meson scdoc \
sudo apt-get install build-essential llvm clang meson scdoc qalc \
ninja-build libfreetype-dev libharfbuzz-dev libcairo-dev \
libpango1.0-dev libwayland-dev wayland-protocols libxkbcommon-dev \
python3-pip
Expand Down Expand Up @@ -59,7 +59,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install build-essential llvm clang meson scdoc \
sudo apt-get install build-essential llvm clang meson scdoc qalc \
ninja-build libfreetype-dev libharfbuzz-dev libcairo-dev \
libpango1.0-dev libwayland-dev wayland-protocols libxkbcommon-dev \
python3-pip
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,9 @@ tags

# Project specific files
build/
src/build/
src/meson-info/
src/meson-logs/
src/compile_commands.json
src/build.ninja
.cache
4 changes: 4 additions & 0 deletions doc/tofi.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,10 @@ options.
>
> Default: true

## MODULES
**module-math**=true|false
> Calculate Math equations inside the Input field. The Calculation result will appear inside the result-suggestions, when Selecting this result it will be copied to clipboard and a notification will be sent

## COLORS

Colors can be specified in the form *RGB*, *RGBA*, *RRGGBB* or
Expand Down
4 changes: 3 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ common_sources = files(
'src/surface.c',
'src/unicode.c',
'src/xmalloc.c',
'src/modules.c',
)

compgen_sources = files(
Expand Down Expand Up @@ -144,6 +145,7 @@ wayland_scanner_dep = dependency('wayland-scanner', native: true)
xkbcommon = dependency('xkbcommon')
glib = dependency('glib-2.0')
gio_unix = dependency('gio-unix-2.0')
libqalculate = dependency('libqalculate')

if wayland_client.version().version_compare('<1.20.0')
add_project_arguments(
Expand Down Expand Up @@ -204,7 +206,7 @@ subdir('test')
executable(
'tofi',
files('src/main.c'), common_sources, wl_proto_src, wl_proto_headers,
dependencies: [librt, libm, libfts, freetype, harfbuzz, cairo, pangocairo, wayland_client, xkbcommon, glib, gio_unix],
dependencies: [librt, libm, libfts, freetype, harfbuzz, cairo, pangocairo, wayland_client, xkbcommon, glib, gio_unix, libqalculate],
install: true
)

Expand Down
14 changes: 14 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,20 @@ bool parse_option(struct tofi *tofi, const char *filename, size_t lineno, const
if (!err) {
tofi->use_scale = val;
}
} else if (strcasecmp(option, "module-math") == 0) {
bool val = parse_bool(filename, lineno, value, &err);
if (!err) {
tofi->modules.math.enabled = val;
}
} else if (strcasecmp(option, "module-search") == 0) {
bool val = parse_bool(filename, lineno, value, &err);
if (!err) {
tofi->modules.search.enabled = val;
}
} else if (strcasecmp(option, "module-search-browser") == 0) {
snprintf(tofi->modules.search.browser, N_ELEM(tofi->modules.search.browser), "%s", value);
} else if (strcasecmp(option, "module-search-engine") == 0) {
snprintf(tofi->modules.search.engine, N_ELEM(tofi->modules.search.engine), "%s", value);
} else {
PARSE_ERROR(filename, lineno, "Unknown option \"%s\"\n", option);
err = true;
Expand Down
6 changes: 6 additions & 0 deletions src/desktop_vec.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "string_vec.h"
#include "unicode.h"
#include "xmalloc.h"
#include "modules.h"

static bool match_current_desktop(char * const *desktop_list, gsize length);

Expand Down Expand Up @@ -148,6 +149,7 @@ struct desktop_entry *desktop_vec_find_sorted(struct desktop_vec *restrict vec,
}

struct string_ref_vec desktop_vec_filter(
struct tofi *tofi,
const struct desktop_vec *restrict vec,
const char *restrict substr,
enum matching_algorithm algorithm)
Expand Down Expand Up @@ -175,6 +177,10 @@ struct string_ref_vec desktop_vec_filter(
}
}
}

// add suggestions form enabled modules
modules_suggest(tofi, substr, &filt);

/*
* Sort the results by this search_score. This moves matches at the beginnings
* of words to the front of the result list.
Expand Down
4 changes: 3 additions & 1 deletion src/desktop_vec.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ void desktop_vec_add_file(struct desktop_vec *desktop, const char *id, const cha

void desktop_vec_sort(struct desktop_vec *restrict vec);
struct desktop_entry *desktop_vec_find_sorted(struct desktop_vec *restrict vec, const char *name);
struct tofi;
struct string_ref_vec desktop_vec_filter(
const struct desktop_vec *restrict vec,
struct tofi *tofi,
const struct desktop_vec *restrict vec,
const char *restrict substr,
enum matching_algorithm algorithm);

Expand Down
54 changes: 45 additions & 9 deletions src/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@

static uint32_t keysym_to_key(xkb_keysym_t sym);
static void add_character(struct tofi *tofi, xkb_keycode_t keycode);
static void delete_character(struct tofi *tofi);
static void delete_prev_character(struct tofi *tofi);
static void delete_next_character(struct tofi *tofi);
static void delete_word(struct tofi *tofi);
static void clear_input(struct tofi *tofi);
static void paste(struct tofi *tofi);
Expand All @@ -25,10 +26,6 @@ static void reset_selection(struct tofi *tofi);

void input_handle_keypress(struct tofi *tofi, xkb_keycode_t keycode)
{
if (tofi->xkb_state == NULL) {
return;
}

bool ctrl = xkb_state_mod_name_is_active(
tofi->xkb_state,
XKB_MOD_NAME_CTRL,
Expand All @@ -42,6 +39,14 @@ void input_handle_keypress(struct tofi *tofi, xkb_keycode_t keycode)
XKB_MOD_NAME_SHIFT,
XKB_STATE_MODS_EFFECTIVE);

if (tofi->xkb_state == NULL) {
return;
}
// Ignore "-char to prevent escaping the commands used for math and search
if (11 == keycode && shift) {
return;
}

uint32_t ch = xkb_state_key_get_utf32(tofi->xkb_state, keycode);

/*
Expand All @@ -64,7 +69,9 @@ void input_handle_keypress(struct tofi *tofi, xkb_keycode_t keycode)
delete_word(tofi);
} else if (key == KEY_BACKSPACE
|| (key == KEY_H && ctrl)) {
delete_character(tofi);
delete_prev_character(tofi);
} else if (key == KEY_DELETE) {
delete_next_character(tofi);
} else if (key == KEY_U && ctrl) {
clear_input(tofi);
} else if (key == KEY_V && ctrl) {
Expand Down Expand Up @@ -114,6 +121,8 @@ static uint32_t keysym_to_key(xkb_keysym_t sym)
switch (sym) {
case XKB_KEY_BackSpace:
return KEY_BACKSPACE;
case XKB_KEY_Delete:
return KEY_DELETE;
case XKB_KEY_w:
return KEY_W;
case XKB_KEY_u:
Expand Down Expand Up @@ -198,7 +207,7 @@ void add_character(struct tofi *tofi, xkb_keycode_t keycode)
entry->input_utf8_length += len;

if (entry->mode == TOFI_MODE_DRUN) {
struct string_ref_vec results = desktop_vec_filter(&entry->apps, entry->input_utf8, tofi->matching_algorithm);
struct string_ref_vec results = desktop_vec_filter(tofi, &entry->apps, entry->input_utf8, tofi->matching_algorithm);
string_ref_vec_destroy(&entry->results);
entry->results = results;
} else {
Expand Down Expand Up @@ -236,15 +245,15 @@ void input_refresh_results(struct tofi *tofi)
entry->input_utf8_length = bytes_written;
string_ref_vec_destroy(&entry->results);
if (entry->mode == TOFI_MODE_DRUN) {
entry->results = desktop_vec_filter(&entry->apps, entry->input_utf8, tofi->matching_algorithm);
entry->results = desktop_vec_filter(tofi, &entry->apps, entry->input_utf8, tofi->matching_algorithm);
} else {
entry->results = string_ref_vec_filter(&entry->commands, entry->input_utf8, tofi->matching_algorithm);
}

reset_selection(tofi);
}

void delete_character(struct tofi *tofi)
void delete_prev_character(struct tofi *tofi)
{
struct entry *entry = &tofi->window.entry;

Expand All @@ -271,6 +280,33 @@ void delete_character(struct tofi *tofi)
input_refresh_results(tofi);
}

void delete_next_character(struct tofi *tofi)
{
struct entry *entry = &tofi->window.entry;

if (entry->input_utf32_length == 0) {
/* No input to delete. */
return;
}

if (entry->cursor_position == entry->input_utf32_length) {
return;
} else if (entry->cursor_position == entry->input_utf32_length) {
// entry->cursor_position--;
entry->input_utf32_length++;
entry->input_utf32[entry->input_utf32_length] = U'\0';
} else {
for (size_t i = entry->cursor_position + 1; i < entry->input_utf32_length - 1; i++) {
entry->input_utf32[i] = entry->input_utf32[i + 1];
}
// entry->cursor_position--;
entry->input_utf32_length--;
entry->input_utf32[entry->input_utf32_length] = U'\0';
}

input_refresh_results(tofi);
}

void delete_word(struct tofi *tofi)
{
struct entry *entry = &tofi->window.entry;
Expand Down
13 changes: 13 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <wayland-client.h>
#include <wayland-util.h>
#include <xkbcommon/xkbcommon.h>
#include "src/modules.h"
#include "tofi.h"
#include "compgen.h"
#include "drun.h"
Expand Down Expand Up @@ -1030,6 +1031,8 @@ static bool do_submit(struct tofi *tofi)
}
}
if (app == NULL) {
if (modules_try_execute(tofi, res, entry->input_utf8))
return true;
log_error("Couldn't find application file! This shouldn't happen.\n");
return false;
}
Expand Down Expand Up @@ -1200,6 +1203,16 @@ int main(int argc, char *argv[])
.require_match = true,
.use_scale = true,
.physical_keybindings = true,
.modules = {
.math = {
.enabled = true
},
.search = {
.enabled = false,
.browser = "firefox",
.engine = "google.com/search"
}
}
};
wl_list_init(&tofi.output_list);
if (getenv("TERMINAL") != NULL) {
Expand Down
97 changes: 97 additions & 0 deletions src/modules.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#include "modules.h"
#include "history.h"
#include "string_vec.h"
#include "unicode.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void module_math_suggestion(const char *restrict query,
struct string_ref_vec *filt) {
char command[128] = "qalc -t -m 1000 \"";
command[sizeof(command) - 1] = '\0'; // Ensure null termination
strncat(command, query, sizeof(command) - 1);
strncat(command, "\"", sizeof(command) - 1);

char result[128] = "";

// execute command
FILE *fp = popen(command, "r");
// limit output to 50 characters
fgets(result, 50, fp);
pclose(fp);

// add module prefix
char finalresult[128] = "=";
strncat(finalresult, result, sizeof(finalresult) - 1);
finalresult[strlen(finalresult) - 1] = '\0'; // Ensure null termination

string_ref_vec_add(filt, utf8_normalize(finalresult));
}

bool module_math_selected(char *suggestion, char *query) {
char notify[128] = "notify-send \"Calculation: ";
// set notification title to be the calculation
strncat(notify, query, sizeof(notify) - 1);
strncat(notify, "\" \"", sizeof(notify) - 1);
// set notification body to be result
strncat(notify, suggestion, sizeof(notify) - 1);
strncat(notify, "\"", sizeof(notify) - 1);

char copy[128] = "wl-copy \"";
strncat(copy, suggestion, sizeof(notify) - 1);
strncat(copy, "\"", sizeof(notify) - 1);

system(copy);
system(notify);

// return is here to avoid an ugly switch
return true;
}

void module_search_suggestion(char *restrict query,
struct string_ref_vec *restrict filt) {
// always display this to avoid duplicate string
string_ref_vec_add(filt, "?search");
}

bool module_search_selected(struct tofi *tofi, char *restrict query) {
char command[128] = "";
strncat(command, tofi->modules.search.browser, sizeof(command)-1);
strncat(command, " \"", sizeof(command)-1);
strncat(command, tofi->modules.search.engine, sizeof(command)-1);
strncat(command, "?q=", sizeof(command) - 1);
strncat(command, query, sizeof(command) - 1);
strncat(command, "\" &", sizeof(command) - 1);

system(command);
// return is here to avoid an ugly switch
return true;
}

void modules_suggest(struct tofi *tofi, char *restrict query,
struct string_ref_vec *filt) {
// prevent modules from suggesting when the input is empty
if (strlen(query) == 0) return;

if (tofi->modules.math.enabled)
module_math_suggestion(query, filt);
if (tofi->modules.search.enabled)
module_search_suggestion(query, filt);
}

bool modules_try_execute(struct tofi *tofi, char *suggestion, char *restrict query) {
char prefix = suggestion[0];
// remove first character (prefix)
suggestion++;
switch (prefix) {
case '=':
if (tofi->modules.math.enabled)
return module_math_selected(suggestion, query);
case '?':
if (tofi->modules.search.enabled)
return module_search_selected(tofi, query);
default:
return false;
}
}
10 changes: 10 additions & 0 deletions src/modules.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef MODULES_H
#define MODULES_H

#include "tofi.h"

void modules_suggest(struct tofi *tofi, char *restrict query,
struct string_ref_vec *filt);
bool modules_try_execute(struct tofi *tofi, char *suggestion, char *restrict query);

#endif /* MKDIRP_H */
Loading