#include "pistachio.h"
void make_argb(u32 color, ARGB *argb) {
argb->a = (float)(0xff & (color >> 24));
argb->r = (float)(0xff & (color >> 16));
argb->g = (float)(0xff & (color >> 8));
argb->b = (float)(0xff & color);
}
void remove_char(char *str, int len, int pos) {
if (pos > 0 && pos <= len) {
memmove(&str[pos-1], &str[pos], len - pos);
str[len-1] = 0;
}
}
int insert_substring(char *str, int len, char *insert, int insert_len, int pos) {
if (len < 0)
len = strlen(str);
if (pos < 0 || pos > len || insert_len <= 0)
return 0;
if (pos == len)
memcpy(&str[pos], insert, insert_len);
else {
memmove(&str[pos + insert_len], &str[pos], len - pos);
memcpy(&str[pos], insert, insert_len);
}
return insert_len;
}
int insert_chars(char *str, int len, char *insert, int insert_len, int pos) {
int add_len = 0;
char add[insert_len];
for (int i = 0; i < insert_len; i++) {
if (glyph_indexof(insert[i]) >= 0)
add[add_len++] = insert[i];
}
return insert_substring(str, len, add, add_len, pos);
}
int remove_backslashes(char *str, int span) {
int len = strlen(str);
if (span < 0)
span = len;
int idx = 0;
for (int i = 0; i < span; i++) {
if (str[i] == '\\')
continue;
str[idx++] = str[i];
}
if (len > span)
memmove(&str[idx], &str[span], len - span + 1); // +1 for null terminator
else
str[idx] = 0;
return idx;
}
int escape_spaces(char *str, int span) {
int len = strlen(str);
if (span < 0)
span = len;
bool was_backslash = false;
for (int i = 0; i < span; i++) {
if (str[i] == ' ' && !was_backslash) {
memmove(&str[i+1], &str[i], len - i);
str[i++] = '\\';
span++;
len++;
}
was_backslash = str[i] == '\\';
}
return span;
}
int find_next_word(char *str, int start, int end) {
bool was_backslash = false;
for (int i = start; i < end; i++) {
if (str[i] == ' ' && !was_backslash)
return i+1;
was_backslash = str[i] == '\\';
}
return start;
}
void find_word(char *str, int idx, int *first, int *last) {
int len = strlen(str);
if (idx >= len)
idx = len-1;
bool seen_non_space = false;
int i = idx;
while (true) {
if (i == 0) {
*first = str[0] == ' ' ? 1 : 0;
break;
}
if (str[i] == ' ' && str[i-1] != '\\' && seen_non_space) {
*first = i+1;
break;
}
if (!seen_non_space)
seen_non_space = str[i] != ' ';
i--;
}
bool was_backslash = false;
i = *first;
while (true) {
if (str[i] == ' ' && !was_backslash) {
*last = i-1;
break;
}
if (i == len-1) {
*last = i;
break;
}
was_backslash = str[i++] == '\\';
}
}
void prepend_word(char *word, char *sentence) {
if (!word || !sentence)
return;
int insert_len = strlen(word) + 1;
if (insert_len <= 1)
return;
memmove(&sentence[insert_len], sentence, strlen(sentence) + 1);
strcpy(sentence, word);
sentence[insert_len-1] = ' ';
}
bool difference_ignoring_backslashes(char *name, char *word, int word_len, int trailing) {
if (!trailing)
return false;
char *search = &word[word_len - trailing];
for (int i = 0; i < trailing && search[i]; i++) {
if (name[i] == '\\')
name++;
if (search[i] == '\\')
search++;
if (name[i] != search[i])
return true;
}
return false;
}
bool enumerate_directory(char *textbox, int cursor, char **word, int *word_length, int *search_length, Listing *list) {
int input_len = strlen(textbox);
if (!input_len || textbox[input_len-1] == ' ')
return true;
int first = 0, last = 0;
find_word(textbox, cursor, &first, &last);
int word_len = last - first + 1;
int d_len = word_len > 10 ? word_len : 10;
char directory[d_len];
memset(directory, 0, d_len);
int search_len = 0;
bool is_command = !(textbox[first] == '/' || textbox[first] == '~');
if (!is_command) {
for (int i = last; i >= first && (textbox[i] != '/' && textbox[i] != '~'); i--)
search_len++;
int extra = 0;
if (word_len - search_len > 1) extra = 1;
d_len = word_len - search_len - extra;
memcpy(directory, &textbox[first], d_len);
directory[d_len] = 0;
remove_backslashes(directory, -1);
}
else {
strcpy(directory, BINARIES_DIR);
search_len = word_len;
}
list_directory(directory, -1, list);
if (word)
*word = &textbox[first];
if (word_length)
*word_length = word_len;
if (search_length)
*search_length = search_len;
return is_command;
}
char *find_completeable_span(Listing *listing, char *word, int word_len, int trailing, int *match_length) {
char *match = NULL;
int match_len = 0;
if (trailing) {
for (int i = 0; i < listing->n_entries; i++) {
char *str = listing->table[i];
if (difference_ignoring_backslashes(str, word, word_len, trailing))
continue;
if (!match) {
match = str;
match_len = strlen(match);
continue;
}
int j;
for (j = trailing; j < match_len && str[j] == match[j]; j++);
match_len = j;
}
}
else if (listing->n_entries == 1) {
match = listing->first;
match_len = strlen(match);
}
if (match_length)
*match_length = match_len;
return match;
}
int complete(char *word, int *word_length, char *match, int match_len, int trailing, bool folder_completion) {
int word_len = *word_length;
int n_spaces = 0;
for (int i = 0; i < trailing; i++) {
if (match[i] == ' ')
n_spaces++;
}
int offset = trailing - n_spaces;
int add = match_len - offset;
if (word_len > 0 && word[0] == '~' && (word_len == 1 || word[1] != '/'))
word_len += insert_substring(word, -1, "/", 1, 1);
word_len += insert_substring(word, -1, &match[offset], add, word_len);
word_len = escape_spaces(word, word_len);
struct stat s;
char *path = get_desugared_path(word, word_len);
// If folder completion is enabled and 'word' refers to a folder, append a forward slash for further tab completion
if (folder_completion && stat(path, &s) == 0 && (s.st_mode & S_IFMT) == S_IFDIR) {
trailing = 0;
if (word[word_len-1] != '/')
word_len += insert_substring(word, -1, "/", 1, word_len);
}
else if (match)
trailing = match_len;
if (word_length)
*word_length = word_len;
return trailing;
}