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;
|
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)
|
void editor_type_goto_line(struct editor* editor)
|
||||||
{
|
{
|
||||||
editor->mode = MODE_GOTO_LINE;
|
editor->mode = MODE_GOTO_LINE;
|
||||||
|
@ -849,6 +857,7 @@ void editor_type_character(struct editor* editor, wchar_t c)
|
||||||
switch ( towlower(c) )
|
switch ( towlower(c) )
|
||||||
{
|
{
|
||||||
case L'c': editor_type_copy(editor); break;
|
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'g': editor_type_goto_line(editor); break;
|
||||||
case L'k': editor_type_cut(editor); break;
|
case L'k': editor_type_cut(editor); break;
|
||||||
case L'o': editor->shift ?
|
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(y < editor->lines_used);
|
||||||
assert(x <= editor->lines[y].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 )
|
if ( y < editor->page_y_offset )
|
||||||
editor->page_y_offset = y;
|
editor->page_y_offset = y;
|
||||||
if ( editor->page_y_offset + editor->viewport_height <= y )
|
if ( editor->page_y_offset + viewport_height <= y )
|
||||||
editor->page_y_offset = y + 1 - editor->viewport_height;
|
editor->page_y_offset = y + 1 - viewport_height;
|
||||||
}
|
}
|
||||||
editor->select_row = y;
|
editor->select_row = y;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013, 2014 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2013, 2014 Jonas 'Sortie' Termansen.
|
||||||
|
* Copyright (c) 2021 Juhani 'nortti' Krekelä.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* 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: ";
|
msg = "Go to line: ";
|
||||||
if ( editor->mode == MODE_COMMAND )
|
if ( editor->mode == MODE_COMMAND )
|
||||||
msg = "Enter miscellaneous command: ";
|
msg = "Enter miscellaneous command: ";
|
||||||
|
if ( editor->mode == MODE_SEARCH )
|
||||||
|
msg = "Search: ";
|
||||||
|
|
||||||
struct terminal_datum* data_line = state->data + (state->height - 1) * state->width;
|
struct terminal_datum* data_line = state->data + (state->height - 1) * state->width;
|
||||||
wchar_t* wcs_msg = convert_mbs_to_wcs(msg);
|
wchar_t* wcs_msg = convert_mbs_to_wcs(msg);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.Dd January 8, 2016
|
.Dd December 13, 2021
|
||||||
.Dt EDITOR 1
|
.Dt EDITOR 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -26,6 +26,8 @@ It supports these keyboard shortcuts:
|
||||||
.Bl -tag -width "12345768"
|
.Bl -tag -width "12345768"
|
||||||
.It Sy Ctrl-C
|
.It Sy Ctrl-C
|
||||||
Copy.
|
Copy.
|
||||||
|
.It Sy Ctrl-F
|
||||||
|
Search for a regular expression.
|
||||||
.It Sy Ctrl-G
|
.It Sy Ctrl-G
|
||||||
Go to line.
|
Go to line.
|
||||||
.It Sy Ctrl-K
|
.It Sy Ctrl-K
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013, 2014 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2013, 2014 Jonas 'Sortie' Termansen.
|
||||||
|
* Copyright (c) 2021 Juhani 'nortti' Krekelä.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -51,6 +52,7 @@ enum editor_mode
|
||||||
MODE_ASK_QUIT,
|
MODE_ASK_QUIT,
|
||||||
MODE_GOTO_LINE,
|
MODE_GOTO_LINE,
|
||||||
MODE_COMMAND,
|
MODE_COMMAND,
|
||||||
|
MODE_SEARCH,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct editor
|
struct editor
|
||||||
|
|
|
@ -18,12 +18,16 @@
|
||||||
* Modal commands.
|
* Modal commands.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <regex.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <wchar.h>
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
|
||||||
#include "command.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);
|
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)
|
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_ASK_QUIT: editor_modal_ask_quit(editor, param); break;
|
||||||
case MODE_GOTO_LINE: editor_modal_goto_line(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_COMMAND: editor_modal_command(editor, param); break;
|
||||||
|
case MODE_SEARCH: editor_modal_search(editor, param); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
free(param);
|
free(param);
|
||||||
|
|
Loading…
Reference in New Issue