Add search to editor(1).
This commit is contained in:
parent
20648e03d7
commit
42f6a359d1
|
@ -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 ?
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(®ex, 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(®ex, 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(®ex);
|
||||
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(®ex, 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(®ex);
|
||||
return;
|
||||
}
|
||||
line++;
|
||||
}
|
||||
|
||||
regfree(®ex);
|
||||
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue