📄 tab.c
字号:
#include "tdestr.h"
#include "common.h"
#include "tdefunc.h"
#include "define.h"
/*
* Name: tab_key
* Purpose: To make the necessary changes after the user types the tab key.
* Date: June 5, 1991
* Passed: window: pointer to current window
* Notes: If in insert mode, then this function adds the required
* number of spaces in the file.
* If not in insert mode, then tab simply moves the cursor right
* the required distance.
*/
int tab_key( WINDOW *window )
{
int spaces; /* the spaces to move to the next tab stop */
char *source; /* source for block move to make room for c */
char *dest; /* destination for block move */
int pad;
int len;
register int rcol;
int old_bcol;
register WINDOW *win; /* put window pointer in a register */
int rc;
win = window;
if (win->ll->len == EOF)
return( OK );
rcol = win->rcol;
old_bcol = win->bcol;
show_ruler_char( win );
/*
* work out the number of spaces to the next tab stop
*/
if (mode.smart_tab)
spaces = next_smart_tab( win );
else
spaces = mode.ltab_size - (rcol % mode.ltab_size);
assert( spaces >= 0 );
assert( spaces < MAX_LINE_LENGTH );
rc = OK;
if (mode.insert && rcol + spaces < g_display.line_length) {
copy_line( win->ll );
detab_linebuff( );
/*
* work out how many characters need to be inserted
*/
len = g_status.line_buff_len;
pad = rcol > len ? rcol - len : 0;
if (len + pad + spaces >= g_display.line_length) {
/*
* line too long to add
*/
error( WARNING, win->bottom_line, ed1 );
rc = ERROR;
g_status.copied = FALSE;
} else {
if (pad > 0 || spaces > 0) {
source = g_status.line_buff + rcol - pad;
dest = source + pad + spaces;
assert( len + pad - rcol >= 0 );
assert( len + pad - rcol < MAX_LINE_LENGTH );
memmove( dest, source, len + pad - rcol );
/*
* if padding was required, then put in the required spaces
*/
assert( pad + spaces >= 0 );
assert( pad + spaces < MAX_LINE_LENGTH );
memset( source, ' ', pad + spaces );
g_status.line_buff_len += pad + spaces;
entab_linebuff( );
}
win->ll->dirty = TRUE;
win->file_info->dirty = GLOBAL;
show_changed_line( win );
rcol += spaces;
win->ccol += spaces;
}
} else if (rcol + spaces <= g_display.line_length) {
/*
* advance the cursor without changing the text underneath
*/
rcol += spaces;
win->ccol += spaces;
}
check_virtual_col( win, rcol, win->ccol );
if (old_bcol != win->bcol) {
make_ruler( win );
show_ruler( win );
}
return( rc );
}
/*
* Name: backtab
* Purpose: To make the necessary changes after the user presses the backtab.
* Date: November 1, 1991
* Passed: window: pointer to current window
* Notes: If in insert mode, then this function subs the required
* number of spaces in the file.
* If not in insert mode, then tab simply moves the cursor left
* the required distance.
*/
int backtab( WINDOW *window )
{
int spaces; /* the spaces to move to the next tab stop */
char *source; /* source for block move to make room for c */
char *dest; /* destination for block move */
int pad;
int len;
register int rcol;
int old_bcol;
register WINDOW *win; /* put window pointer in a register */
win = window;
rcol = win->rcol;
if (win->ll->len == EOF || win->rcol == 0)
return( OK );
old_bcol = win->bcol;
show_ruler_char( win );
/*
* work out the number of spaces to the previous tab stop
*/
if (mode.smart_tab)
spaces = prev_smart_tab( win );
else
spaces = win->rcol % mode.ltab_size;
if (spaces == 0)
spaces = mode.ltab_size;
copy_line( win->ll );
detab_linebuff( );
len = g_status.line_buff_len;
if (mode.insert && rcol - spaces < len) {
pad = rcol > len ? rcol - len : 0;
if (pad > 0 || spaces > 0) {
/*
* if padding was required, then put in the required spaces
*/
if (pad > 0) {
assert( rcol - pad >= 0 );
assert( pad < MAX_LINE_LENGTH );
source = g_status.line_buff + rcol - pad;
dest = source + pad;
assert( pad >= 0 );
assert( pad < MAX_LINE_LENGTH );
memmove( dest, source, pad );
memset( source, ' ', pad );
g_status.line_buff_len += pad;
}
source = g_status.line_buff + rcol;
dest = source - spaces;
assert( len + pad - rcol >= 0 );
assert( len + pad - rcol < MAX_LINE_LENGTH );
memmove( dest, source, len + pad - rcol );
g_status.line_buff_len -= spaces;
entab_linebuff( );
}
win->ll->dirty = TRUE;
win->file_info->dirty = GLOBAL;
show_changed_line( win );
rcol -= spaces;
win->ccol -= spaces;
} else {
/*
* move the cursor without changing the text underneath
*/
rcol -= spaces;
if (rcol < 0)
rcol = 0;
win->ccol -= spaces;
}
check_virtual_col( win, rcol, win->ccol );
if (old_bcol != win->bcol) {
make_ruler( win );
show_ruler( win );
}
return( OK );
}
/*
* Name: next_smart_tab
* Purpose: To find next smart tab
* Date: June 5, 1992
* Passed: window: pointer to the current window
* Notes: To find a smart tab 1) find the first non-blank line above the
* current line, 2) find the first non-blank character after
* column of the cursor.
*/
int next_smart_tab( WINDOW *window )
{
register int spaces; /* the spaces to move to the next tab stop */
text_ptr s; /* pointer to text */
line_list_ptr ll;
register WINDOW *win; /* put window pointer in a register */
int len;
/*
* find first previous non-blank line above the cursor.
*/
win = window;
ll = win->ll->prev;
while (ll != NULL && is_line_blank( ll->line, ll->len ))
ll = ll->prev;
if (ll != NULL) {
s = ll->line;
/*
* if cursor is past the eol of the smart line, lets find the
* next fixed tab.
*/
if (window->rcol >= find_end( s, ll->len ))
spaces = mode.ltab_size - (window->rcol % mode.ltab_size);
else {
len = ll->len;
s = detab_a_line( s, &len );
spaces = 0;
s = s + window->rcol;
len -= window->rcol;
/*
* if we are on a word, find the end of it.
*/
while (*s != ' ' && len > 0) {
++s;
++spaces;
--len;
}
/*
* now find the start of the next word.
*/
if (len > 0)
while (*s == ' ' && len > 0) {
++s;
++spaces;
--len;
}
}
} else
spaces = mode.ltab_size - (window->rcol % mode.ltab_size);
return( spaces );
}
/*
* Name: prev_smart_tab
* Purpose: To find previous smart tab
* Date: June 5, 1992
* Passed: window: pointer to the current window
* Notes: To find a smart tab 1) find the first non-blank line above the
* current line, 2) find the first non-blank character before
* column of the cursor.
* there are several cases to consider: 1) the cursor is past the
* the end of the smart line, 2) the smart pointer is in the
* middle of a word, 3) there are no more words between the
* smart pointer and the beginning of the line.
*/
int prev_smart_tab( WINDOW *window )
{
register int spaces; /* the spaces to move to the next tab stop */
text_ptr s; /* pointer to text */
int len;
line_list_ptr ll;
WINDOW *win; /* put window pointer in a register */
/*
* find first previous non-blank line above the cursor, if it exists.
*/
win = window;
ll = win->ll->prev;
while (ll != NULL && is_line_blank( ll->line, ll->len ))
ll = ll->prev;
if (ll != NULL) {
s = ll->line;
/*
* if there are no words between the cursor and column 1 of the
* smart tab line, find previous fixed tab.
*/
if (window->rcol < first_non_blank( s, ll->len ))
spaces = window->rcol % mode.ltab_size;
else {
len = ll->len;
if (mode.inflate_tabs)
s = detab_a_line( s, &len );
/*
* now, we need to figure the initial pointer and space.
* if the cursor is past the eol of the smart line, then
* set the smart pointer "s" to the end of line and "spaces" to
* the number of characters between the cursor and the eol
* of the smart line. otherwise, set the smart pointer "s" to
* the column of the cursor and "spaces" to 0.
*/
if (len < window->rcol) {
s += len;
spaces = window->rcol - len;
} else {
len = window->rcol;
s += window->rcol;
spaces = 0;
}
while (*(s-1) == ' ' && len > 0) {
--s;
++spaces;
--len;
}
/*
* now find the beginning of the first word at eol.
*/
while (*(s-1) != ' ' && len > 0) {
--s;
++spaces;
--len;
}
if (len == 0 && *s == ' ')
spaces = window->rcol % mode.ltab_size;
if (spaces > window->rcol)
spaces = window->rcol;
}
} else
spaces = window->rcol % mode.ltab_size;
/*
* spaces cannot be negative.
*/
if (spaces < 0)
spaces = 0;
return( spaces );
}
/*
* Name: entab
* Purpose: To compress spaces to tabs
* Date: October 31, 1992
* Passed: s: pointer to current line
* Returns: pointer to tabout_buf
* Notes: the text_ptr can point to either the g_status.line_buff or
* a line in the main text buffer.
* this function assumes that a '\n' terminates the line.
*/
text_ptr entab( text_ptr s, int len )
{
int tab_size;
int last_col;
int space;
register int col;
text_ptr to;
assert( s != NULL );
assert( len >= 0 );
assert( len < MAX_LINE_LENGTH );
tab_size = mode.ptab_size;
to = (text_ptr)g_status.tabout_buff;
if (s == NULL)
g_status.tabout_buff_len = 0;
else {
g_status.tabout_buff_len = len;
for (last_col=col=0; ; s++, len--) {
if (len == 0) {
/*
* when we reach the eol, compress trailing spaces to tabs.
* the un_copy_line function is responsible for trimming
* trailing space.
*/
if (col != last_col) {
while (last_col < col) {
space = tab_size - last_col % tab_size;
if (space <= 1) {
*to++ = ' ';
last_col++;
} else if (last_col + space <= col) {
*to++ = '\t';
last_col += space;
g_status.tabout_buff_len -= (space - 1);
} else {
*to++ = ' ';
last_col++;
}
}
}
/*
* stop entabbing when we get to EOL
*/
break;
} else if (*s == ' ')
col++;
else {
if (col != last_col) {
while (last_col < col) {
space = tab_size - last_col % tab_size;
/*
* when space == 1, forget about emmitting a tab
* for 1 space.
*/
if (space <= 1) {
*to++ = ' ';
last_col++;
} else if (last_col + space <= col) {
*to++ = '\t';
last_col += space;
g_status.tabout_buff_len -= (space - 1);
} else {
*to++ = ' ';
last_col++;
}
}
}
/*
* if *s == tab, then adjust the col pointer
*/
if (*s == '\t')
col = col + tab_size - (col % tab_size);
else
++col;
last_col = col;
*to++ = *s;
/*
* when we see a quote character, stop entabbing.
*/
if (*s == '\"' || *s == '\'') {
while (len > 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -