Add search to editor(1).

This commit is contained in:
Juhani Krekelä 2021-10-31 02:55:26 +03:00
parent 20648e03d7
commit 42f6a359d1
6 changed files with 118 additions and 4 deletions

View File

@ -649,6 +649,14 @@ void editor_type_edit(struct editor* editor)
editor->mode = MODE_EDIT;
}
void editor_type_search(struct editor* editor)
{
editor->mode = MODE_SEARCH;
editor->modal_used = 0;
editor->modal_cursor = 0;
editor->modal_error = false;
}
void editor_type_goto_line(struct editor* editor)
{
editor->mode = MODE_GOTO_LINE;
@ -849,6 +857,7 @@ void editor_type_character(struct editor* editor, wchar_t c)
switch ( towlower(c) )
{
case L'c': editor_type_copy(editor); break;
case L'f': editor_type_search(editor); break;
case L'g': editor_type_goto_line(editor); break;
case L'k': editor_type_cut(editor); break;
case L'o': editor->shift ?

View File

@ -30,12 +30,17 @@ void editor_select_set(struct editor* editor, size_t y, size_t x)
{
assert(y < editor->lines_used);
assert(x <= editor->lines[y].used);
if ( editor->viewport_height )
size_t viewport_height = editor->viewport_height;
// Account for the modal shrinking the viewport by one line.
if ( editor->mode != MODE_EDIT && viewport_height )
viewport_height--;
if ( viewport_height )
{
if ( y < editor->page_y_offset )
editor->page_y_offset = y;
if ( editor->page_y_offset + editor->viewport_height <= y )
editor->page_y_offset = y + 1 - editor->viewport_height;
if ( editor->page_y_offset + viewport_height <= y )
editor->page_y_offset = y + 1 - viewport_height;
}
editor->select_row = y;

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2013, 2014 Jonas 'Sortie' Termansen.
* Copyright (c) 2021 Juhani 'nortti' Krekelä.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -267,6 +268,8 @@ void render_editor(struct editor* editor, struct terminal_state* state)
msg = "Go to line: ";
if ( editor->mode == MODE_COMMAND )
msg = "Enter miscellaneous command: ";
if ( editor->mode == MODE_SEARCH )
msg = "Search: ";
struct terminal_datum* data_line = state->data + (state->height - 1) * state->width;
wchar_t* wcs_msg = convert_mbs_to_wcs(msg);

View File

@ -1,4 +1,4 @@
.Dd January 8, 2016
.Dd December 13, 2021
.Dt EDITOR 1
.Os
.Sh NAME
@ -26,6 +26,8 @@ It supports these keyboard shortcuts:
.Bl -tag -width "12345768"
.It Sy Ctrl-C
Copy.
.It Sy Ctrl-F
Search for a regular expression.
.It Sy Ctrl-G
Go to line.
.It Sy Ctrl-K

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2013, 2014 Jonas 'Sortie' Termansen.
* Copyright (c) 2021 Juhani 'nortti' Krekelä.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -51,6 +52,7 @@ enum editor_mode
MODE_ASK_QUIT,
MODE_GOTO_LINE,
MODE_COMMAND,
MODE_SEARCH,
};
struct editor

View File

@ -18,12 +18,16 @@
* Modal commands.
*/
#include <sys/types.h>
#include <ctype.h>
#include <regex.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <wctype.h>
#include "command.h"
@ -351,6 +355,94 @@ void editor_modal_command_config(struct editor* editor, const char* cmd)
editor_modal_line_numbering(editor, cmd);
}
bool match_line(regex_t* regex, const wchar_t* line, size_t used,
bool start_of_line, size_t* start, size_t *end)
{
if ( !used )
return false;
char* buffer = calloc(used, MB_CUR_MAX);
if ( !buffer )
return false;
size_t buffer_used = 0;
mbstate_t ps = {0};
for ( size_t i = 0; i < used; i++ )
buffer_used += wcrtomb(&buffer[buffer_used], line[i], &ps);
regmatch_t start_end[] = {{.rm_so = 0, .rm_eo = buffer_used}};
int flags = start_of_line ? REG_STARTEND : REG_STARTEND | REG_NOTBOL;
int no_match = regexec(regex, buffer, 1, start_end, flags);
free(buffer);
if ( no_match )
return false;
char mb[MB_CUR_MAX];
memset(&ps, 0, sizeof(ps));
size_t wc_offset = 0;
regoff_t mb_offset = 0;
for ( ; mb_offset < start_end[0].rm_so; wc_offset++ )
mb_offset += wcrtomb(mb, line[wc_offset], &ps);
*start = wc_offset;
for ( ; mb_offset < start_end[0].rm_eo; wc_offset++ )
mb_offset += wcrtomb(mb, line[wc_offset], &ps);
*end = wc_offset;
return true;
}
void editor_modal_search(struct editor* editor, const char* search)
{
if ( !search[0] )
{
editor_type_edit(editor);
return;
}
regex_t regex;
if ( regcomp(&regex, search, REG_EXTENDED) )
{
editor->modal_error = true;
return;
}
size_t column = editor->cursor_column + 1;
if ( column < editor->lines[editor->cursor_row].used )
{
const wchar_t* line = &editor->lines[editor->cursor_row].data[column];
size_t length = editor->lines[editor->cursor_row].used - column;
size_t match, match_end;
if ( match_line(&regex, line, length, false, &match, &match_end) )
{
editor_cursor_set(editor, editor->cursor_row, match + column);
editor_select_set(editor, editor->cursor_row, match_end + column);
regfree(&regex);
return;
}
}
size_t line = editor->cursor_row + 1;
size_t remaining = editor->lines_used;
while ( remaining-- )
{
if ( editor->lines_used <= line )
line = 0;
size_t match, match_end;
if ( match_line(&regex, editor->lines[line].data,
editor->lines[line].used, true, &match, &match_end) )
{
editor_cursor_set(editor, line, match);
editor_select_set(editor, line, match_end);
regfree(&regex);
return;
}
line++;
}
regfree(&regex);
editor->modal_error = true;
}
void editor_modal_character(struct editor* editor, wchar_t c)
{
@ -382,6 +474,7 @@ void editor_modal_character(struct editor* editor, wchar_t c)
case MODE_ASK_QUIT: editor_modal_ask_quit(editor, param); break;
case MODE_GOTO_LINE: editor_modal_goto_line(editor, param); break;
case MODE_COMMAND: editor_modal_command(editor, param); break;
case MODE_SEARCH: editor_modal_search(editor, param); break;
default: break;
}
free(param);