popup and diagnose ui

This commit is contained in:
2026-06-02 13:00:13 +02:00
parent a8b2960eb4
commit 2738bc8042
25 changed files with 587 additions and 461 deletions
+67 -56
View File
@@ -2,32 +2,27 @@
#include "../include/define.h"
#include "../include/editor_op.h"
#include "../include/output.h"
#include "include/data.h"
#include "include/buffer.h"
#include "include/builtins.h"
#include "../include/completion.h"
#include "include/data.h"
#include "include/split_screen.h"
#include "include/completion.h"
#include "include/lsp_ui.h"
#include <ctype.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "include/terminal.h"
#include "include/utf8.h"
#include "include/utils.h"
extern struct editorConfig E;
/**
* @file input.c
* @brief Input handling module for the Beluga text editor
* @details Manages user input processing, key bindings, cursor movement, and file path completion
* @details Manages user input processing, key bindings, cursor movement, and
* file path completion
*/
/**
@@ -36,7 +31,8 @@ extern struct editorConfig E;
* the first file or directory entry that matches the filename prefix.
* Appends a trailing slash for directory entries.
* @param path The file path to complete (can be relative or absolute)
* @return Pointer to the completed file path (dynamically allocated), or NULL if:
* @return Pointer to the completed file path (dynamically allocated), or NULL
* if:
* - path ends with '/' (already a directory)
* - no matching entries found
* - directory cannot be opened
@@ -63,7 +59,7 @@ const char *fileCompletion(const char *path) {
if (last_slash) {
dir_len = last_slash - path + 1; // length of dir_path
strncpy(directory, path, dir_len);
predict_len = strlen(path) - dir_len;
predict_len = (int)(strlen(path) - dir_len);
strncpy(predict, last_slash + 1, predict_len);
directory[dir_len] = '\0';
predict[predict_len] = '\0';
@@ -102,9 +98,9 @@ const char *fileCompletion(const char *path) {
/**
* @brief Displays an interactive prompt and returns user input
* @details Allows the user to enter text in a prompt with optional path completion
* via Tab key. Supports backspace, delete, and escape key handling. Dynamically
* allocates memory for the input buffer.
* @details Allows the user to enter text in a prompt with optional path
* completion via Tab key. Supports backspace, delete, and escape key handling.
* Dynamically allocates memory for the input buffer.
* @param prompt The prompt message format string (printf-style)
* @param placeHolder Initial text to display in the input buffer
* @param bPathMode If non-zero, enables Tab key file path completion
@@ -154,8 +150,7 @@ char *editorPrompt(char *prompt, char *placeHolder, char bPathMode) {
strcpy(path, buf);
}
memset(buf, 0, 256);
buf_len = 0;
char * buf_complete = (char *) fileCompletion(path);
char *buf_complete = (char *)fileCompletion(path);
strcpy(buf, buf_complete);
bFree(buf_complete);
buf_len = strlen(buf);
@@ -166,14 +161,12 @@ char *editorPrompt(char *prompt, char *placeHolder, char bPathMode) {
buf_size *= 2;
buf = bRealloc(buf, buf_size);
}
buf[buf_len++] = c;
buf[buf_len++] = (char)c;
buf[buf_len] = '\0';
}
}
}
/**
* @brief Executes the command bound to a key sequence
* @details Searches the keybinding table for a matching key sequence and
@@ -210,56 +203,62 @@ int executeKeyBind(char *key_sequence) {
* and either executes the bound command or inserts the character. Resets
* the quit buffer counter on successful key processing.
* @note Updates global editor state E
* @note Calls editorReadKey() to get input and editorInsertChar() for unbound keys
* @note Calls editorReadKey() to get input and editorInsertChar() for unbound
* keys
*/
void editorProcessKeypress() {
int c = editorReadKey();
char key_sequence[8];
if (E.lsp_client && E.lsp_completion.visible) {
if (c == ARROW_UP || c == CTRL_KEY('p')) {
if (E.lsp_completion.selected > 0)
E.lsp_completion.selected--;
return; // consumed, redraw on next loop
}
if (c == ARROW_DOWN || c == CTRL_KEY('n')) {
if (E.lsp_completion.selected < E.lsp_completion.count - 1)
E.lsp_completion.selected++;
if (E.constantes.LSP) {
if (c == LSP_WAKE_KEY)
return;
}
if (c == '\r') {
CompletionItem *item = &E.lsp_completion.items[E.lsp_completion.selected];
EditorPane *active = splitScreenGetActivePane();
struct buffer_t *buf = bufferFindById(active->buffer_id);
if (E.lsp_client && E.lsp_completion.visible) {
if (c == ARROW_UP || c == CTRL_KEY('p')) {
if (E.lsp_completion.selected > 0)
E.lsp_completion.selected--;
return; // consumed, redraw on next loop
}
if (c == ARROW_DOWN || c == CTRL_KEY('n')) {
if (E.lsp_completion.selected < E.lsp_completion.count - 1)
E.lsp_completion.selected++;
return;
}
if (c == '\r') {
CompletionItem *item =
&E.lsp_completion.items[E.lsp_completion.selected];
EditorPane *active = splitScreenGetActivePane();
struct buffer_t *buf = bufferFindById(active->buffer_id);
// Find how many chars the user already typed by looking at the
// current word (chars before cursor on the same line)
int file_col = active->cursor_x + active->x_offset;
row_t *row = &buf->row[active->cursor_y + active->y_offset];
// Find how many chars the user already typed by looking at the
// current word (chars before cursor on the same line)
int file_col = active->cursor_x + active->x_offset;
row_t *row = &buf->row[active->cursor_y + active->y_offset];
// Walk backwards from cursor to find start of current word
int word_start = file_col;
while (word_start > 0 &&
(isalnum((unsigned char)row->chars[word_start - 1]) ||
row->chars[word_start - 1] == '_'))
word_start--;
// Walk backwards from cursor to find start of current word
int word_start = file_col;
while (word_start > 0 &&
(isalnum((unsigned char)row->chars[word_start - 1]) ||
row->chars[word_start - 1] == '_'))
word_start--;
int already_typed = file_col - word_start; // chars user already typed
int already_typed = file_col - word_start; // chars user already typed
// Insert only the suffix — what comes after what's already typed
const char *suffix = item->label + already_typed;
for (int i = 0; suffix[i]; i++)
bufferInsertBytes(&suffix[i], 1);
// Insert only the suffix — what comes after what's already typed
const char *suffix = item->label + already_typed;
for (int i = 0; suffix[i]; i++)
bufferInsertBytes(&suffix[i], 1);
E.lsp_completion.visible = 0;
return;
}
if (c == ESCAPE) {
E.lsp_completion.visible = 0;
return;
}
// Any other key: dismiss popup and fall through to normal handling
E.lsp_completion.visible = 0;
return;
}
if (c == ESCAPE) {
E.lsp_completion.visible = 0;
return;
}
// Any other key: dismiss popup and fall through to normal handling
E.lsp_completion.visible = 0;
}
if (executeKeyBind(keyToString(c))) {
@@ -268,5 +267,17 @@ void editorProcessKeypress() {
int seq_len = utf8Encode(c, key_sequence);
appDebug("key seq : %s\n", key_sequence);
bufferInsertBytes(key_sequence, seq_len);
if (E.constantes.LSP && is_word_char(key_sequence)) {
EditorPane *active = splitScreenGetActivePane();
struct buffer_t *buffer = bufferFindById(active->buffer_id);
if (E.lsp_client && E.lsp_client->state == LSP_READY) {
lspDidChange(E.lsp_client, buffer);
E.lsp_client->completion_just_arrived = 0; // consume the flag
}
buffer->b_has_changed = 0;
editorAutoComplete(lisp_null(), &E.ctx_error, E.ctx);
}
E.quit_times_buffer = E.constantes.QUIT_TIMES;
}