📄 view.c
字号:
view_set_color (view, DEF_COLOR);
}
/* Very last thing */
if (view->growing_buffer && from+1 == view->last_byte)
get_byte (view, from+1);
}
#ifdef HAVE_TK
view_gotoyx (view, view->current_line+1, 0);
#endif
}
view->last = from;
view_thaw (view);
return from;
}
void
view_place_cursor (WView *view)
{
int shift;
if (view->view_side == view_side_left)
shift = view->nib_shift;
else
shift = 0;
widget_move (&view->widget, view->cursor_row, view->cursor_col + shift);
}
void
view_update (WView *view)
{
static int dirt_limit = 1;
if (view->dirty > dirt_limit){
/* Too many updates skipped -> force a update */
display (view);
view_status (view);
view->dirty = 0;
/* Raise the update skipping limit */
dirt_limit++;
if (dirt_limit > max_dirt_limit)
dirt_limit = max_dirt_limit;
}
if (view->dirty){
if (is_idle ()){
/* We have time to update the screen properly */
display (view);
view_status (view);
view->dirty = 0;
if (dirt_limit > 1)
dirt_limit--;
} else {
/* We are busy -> skipping full update,
only the status line is updated */
view_status (view);
}
/* Here we had a refresh, if fast scrolling does not work
restore the refresh, although this should not happen */
}
}
static inline void
my_define (Dlg_head *h, int idx, char *text,
void (*fn)(WView *), WView *view)
{
define_label_data (h, (Widget *) view, idx, text, (buttonbarfn) fn, view);
}
/* }}} */
/* {{{ Movement functions */
/* If the last parameter is nonzero, it means we want get the count of lines
from current up to the the upto position inclusive */
static long
move_forward2 (WView *view, long current, int lines, long upto)
{
long p, q;
int line;
int col = 0;
if (view->hex_mode){
p = current + lines * view->bytes_per_line;
p = (p >= view->last_byte) ? current : p;
if (lines == 1) {
q = view->edit_cursor + view->bytes_per_line;
line = q / view->bytes_per_line;
col = (view->last_byte-1) / view->bytes_per_line;
view->edit_cursor = (line > col) ? view->edit_cursor : q;
view->edit_cursor = (view->edit_cursor < view->last_byte) ?
view->edit_cursor : view->last_byte-1;
q = current + ((LINES-2) * view->bytes_per_line);
p = (view->edit_cursor < q) ? current : p;
} else {
view->edit_cursor = (view->edit_cursor < p) ?
p : view->edit_cursor;
}
return p;
} else {
if (upto){
lines = -1;
q = upto;
} else
q = view->last_byte;
if (get_byte (view, q) != '\n')
q++;
for (line = col = 0, p = current; p < q; p++){
int c;
if (lines != -1 && line >= lines)
return p;
c = get_byte (view, p);
if (view->wrap_mode){
if (c == '\r')
continue; /* This characters is never displayed */
else if (c == '\t')
col = ((col - view->have_frame)/8)*8 +8+ view->have_frame;
else
col++;
if (view->viewer_nroff_flag && c == '\b'){
if (p + 1 < view->last_byte
&& is_printable (get_byte (view, p + 1))
&& p > view->first
&& is_printable (get_byte (view, p - 1)))
col -= 2;
} else if (col == vwidth){
/* FIXME: the c in is_printable was a p, that is a bug,
I suspect I got that fix from Jakub, same applies
for d. */
int d = get_byte (view, p+2);
if (p + 2 >= view->last_byte || !is_printable (c) ||
!view->viewer_nroff_flag || get_byte (view, p + 1) != '\b' ||
!is_printable (d)){
col = 0;
if (c == '\n' || get_byte (view, p+1) != '\n')
line++;
}
} else if (c == '\n'){
line++;
col = 0;
}
} else if (c == '\n')
line++;
}
if (upto)
return line;
}
return current;
}
/* returns the new current pointer */
/* Cause even the forward routine became very complex, we in the wrap_mode
just find the nearest '\n', use move_forward2(p, 0, q) to get the count
of lines up to there and then use move_forward2(p, something, 0), which we
return */
static long
move_backward2 (WView *view, long current, int lines)
{
long p, q, pm;
int line;
if (!view->hex_mode && current == view->first)
return current;
if (view->hex_mode){
p = current - lines * view->bytes_per_line;
p = (p < view->first) ? view->first : p;
if (lines == 1) {
q = view->edit_cursor - view->bytes_per_line;
view->edit_cursor = (q < view->first) ? view->edit_cursor : q;
p = (view->edit_cursor >= current) ? current : p;
} else {
q = p + ((LINES-2) * view->bytes_per_line);
view->edit_cursor = (view->edit_cursor >= q) ?
p : view->edit_cursor;
}
return p;
} else {
if (current == view->last_byte
&& get_byte (view, current - 1) != '\n')
/* There is one virtual '\n' at the end,
so that the last line is shown */
line = 1;
else
line = 0;
for (q = p = current - 1; p >= view->first; p--)
if (get_byte (view, p) == '\n' || p == view->first) {
pm = p > view->first ? p + 1 : view->first;
if (!view->wrap_mode){
if (line == lines)
return pm;
line++;
} else {
line += move_forward2 (view, pm, 0, q);
if (line >= lines){
if (line == lines)
return pm;
else
return move_forward2 (view, pm, line - lines, 0);
}
q = p + 1;
}
}
}
return p > view->first ? p : view->first;
}
void
view_move_backward (WView *view, int i)
{
view->search_start = view->start_display =
move_backward2 (view, view->start_display, i);
view->found_len = 0;
view->last = view->first + ((LINES-2) * view->bytes_per_line);
view->dirty++;
}
static long
get_bottom_first (WView *view, int do_not_cache, int really)
{
int bottom_first;
if (!have_fast_cpu && !really)
return INT_MAX;
if (!do_not_cache && view->bottom_first != -1)
return view->bottom_first;
/* Force loading */
if (view->growing_buffer){
int old_last_byte;
old_last_byte = -1;
while (old_last_byte != view->last_byte){
old_last_byte = view->last_byte;
get_byte (view, view->last_byte+VIEW_PAGE_SIZE);
}
}
bottom_first = move_backward2 (view, view->last_byte, vheight - 1);
if (view->hex_mode)
bottom_first = (bottom_first + view->bytes_per_line - 1)
/ view->bytes_per_line * view->bytes_per_line;
view->bottom_first = bottom_first;
return view->bottom_first;
}
void
view_move_forward (WView *view, int i)
{
view->start_display = move_forward2 (view, view->start_display, i, 0);
if (!view->reading_pipe && view->start_display > get_bottom_first (view, 0, 0))
view->start_display = view->bottom_first;
view->search_start = view->start_display;
view->found_len = 0;
view->last = view->first + ((LINES-2) * view->bytes_per_line);
view->dirty++;
}
static void
move_to_top (WView *view)
{
view->search_start = view->start_display = view->first;
view->found_len = 0;
view->last = view->first + ((LINES-2) * view->bytes_per_line);
view->nib_shift = 0;
view->edit_cursor = view->start_display;
view->dirty++;
}
static void
move_to_bottom (WView *view)
{
view->search_start = view->start_display = get_bottom_first (view, 0, 1);
view->found_len = 0;
view->last = view->first + ((LINES-2) * view->bytes_per_line);
view->edit_cursor = (view->edit_cursor < view->start_display) ?
view->start_display : view->edit_cursor;
view->dirty++;
}
/* Scroll left/right the view panel functions */
static void
move_right (WView *view)
{
if (view->wrap_mode && !view->hex_mode)
return;
if (view->hex_mode) {
view->last = view->first + ((LINES-2) * view->bytes_per_line);
if (view->hex_mode && view->view_side == view_side_left) {
view->nib_shift = 1 - view->nib_shift;
if (view->nib_shift == 1)
return;
}
view->edit_cursor = (++view->edit_cursor < view->last_byte) ?
view->edit_cursor : view->last_byte - 1;
if (view->edit_cursor >= view->last) {
view->edit_cursor -= view->bytes_per_line;
view_move_forward(view, 1);
}
} else
if (--view->start_col > 0)
view->start_col = 0;
view->dirty++;
}
static void
move_left (WView *view)
{
if (view->wrap_mode && !view->hex_mode)
return;
if (view->hex_mode) {
if (view->hex_mode && view->view_side == view_side_left) {
view->nib_shift = 1 - view->nib_shift;
if (view->nib_shift == 0)
return;
}
view->edit_cursor = (--view->edit_cursor < view->first) ?
view->first : view->edit_cursor;
if (view->edit_cursor < view->start_display) {
view->edit_cursor += view->bytes_per_line;
view_move_backward(view, 1);
}
} else
if (++view->start_col > 0)
view->start_col = 0;
view->dirty++;
}
/* }}} */
/* {{{ Search routines */
/* Case insensitive search of text in data */
static int
icase_search_p (WView *view, char *text, char *data, int nothing)
{
int p = 0, lng;
char *q;
p = (q = _icase_search (text, data, &lng)) != 0;
if (p) {
view->found_len = lng;
view->search_start = q - data - view->found_len;
}
return p;
}
static char *
grow_string_buffer (char *text, int *size)
{
char *new;
int old_size = *size;
/* The grow steps */
*size += 160;
new = xmalloc (*size, "grow_string_buffer");
if (text){
strncpy (new, text, old_size);
free (text);
} else {
*new = 0;
}
return new;
}
static char *
get_line_at (WView *view, long *p)
{
char *buffer = 0;
int buffer_size, usable_size;
int ch;
int direction;
long pos = *p;
long i;
direction = view->direction;
buffer_size = usable_size = 0;
i = ch = 0;
for (;pos >= 0 && (ch = get_byte (view, pos))!= -1; pos += direction, i++){
/* skip over all the possible zeros in the file */
if (ch == 0 && i == 0){
while (pos >= 0 && ((ch = get_byte (view, pos)) != -1) && ch == 0)
pos+= direction;
if (ch == -1)
break;
}
if (i == usable_size){
buffer = grow_string_buffer (buffer, &buffer_size);
usable_size = buffer_size - 2;
buffer [0] = ' '; /* This makes possible strcpy of buffer */
}
buffer [i+1] = ch;
if (ch == '\n' || !ch || ch == -1){
pos += direction; i++;
break;
}
}
if (buffer){
i--;
buffer [0] = ' ';
buffer [i+1] = 0;
/* If we are searching backwards, reverse the string */
if (view->direction < 0)
reverse_string (buffer);
}
*p = pos;
return buffer;
}
/** Search status optmizations **/
/* The number of bytes between percent increments */
int update_steps;
/* Last point where we updated the status */
long update_activate;
static void
search_update_steps (WView *view)
{
if (view->s.st_size)
update_steps = 40000;
else
update_steps = view->last_byte / 100;
/* Do not update the percent display but every 20 ks */
if (update_steps < 20000)
update_steps = 20000;
}
static void
search (WView *view, char *text, int (*search)(WView *, char *, char *, int))
{
int w = view->widget.cols - (view->have_frame * 2);
char *s = NULL; /* The line we read from the view buffer */
long p, beginning;
int ch;
int isatbeg; /* Nonzero means we start search at beginning of some line */
int found_len, search_start;
Dlg_head *d = 0;
int search_status;
/* Used to keep track of where the line starts, when looking forward */
/* is the index before transfering the line; the reverse case uses */
/* the position returned after the line has been read */
long forward_line_start;
long reverse_line_start;
long t;
/* Clear interrupt status */
got_interrupt ();
if (verbose){
d = message (D_INSERT, _(" Search "), _("Searching %s"), text);
mc_refresh ();
}
ch = 0;
if (view->direction == 1){
p = view->found_len ? view->search_start + 1 : view->search_start;
} else {
p = (view->found_len ? view->search_start : view->last) - 1;
}
beginning = p;
isatbeg = view->found_len == 0;
found_len = view->found_len;
search_start = view->search_start;
/* Compute the percent steps */
search_update_steps (view);
update_activate = 0;
for (; ; isatbeg = 1, free (s)){
#ifdef PORT_HAS_FLUSH_EVENTS
static int count;
if ((count++ % 32) == 0)
x_flush_events ();
if (!d->running)
break;
#endif
if (p >= update_activate){
update_activate += update_steps;
if (verbose){
view_percent (view, p, w);
mc_refresh ();
}
if (got_interrupt ())
break;
}
forward_line_start = p;
disable_interrupt_key ();
s = get_line_at (view, &p);
reverse_line_start = p;
enable_interrupt_key ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -