* tiny vi.c: A small 'vi' clone
* Copyright (C) 2000, 2001 Sterling Huxley <sterling@europa.com>
*
- * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
/*
/* vt102 typical ESC sequence */
/* terminal standout start/normal ESC sequence */
-static const char SOs[] ALIGN1 = "\033[7m";
-static const char SOn[] ALIGN1 = "\033[0m";
+#define SOs "\033[7m"
+#define SOn "\033[0m"
/* terminal bell sequence */
-static const char bell[] ALIGN1 = "\007";
+#define bell "\007"
/* Clear-end-of-line and Clear-end-of-screen ESC sequence */
-static const char Ceol[] ALIGN1 = "\033[0K";
-static const char Ceos[] ALIGN1 = "\033[0J";
+#define Ceol "\033[K"
+#define Ceos "\033[J"
/* Cursor motion arbitrary destination ESC sequence */
-static const char CMrc[] ALIGN1 = "\033[%d;%dH";
+#define CMrc "\033[%u;%uH"
/* Cursor motion up and down ESC sequence */
-static const char CMup[] ALIGN1 = "\033[A";
-static const char CMdown[] ALIGN1 = "\n";
+#define CMup "\033[A"
+#define CMdown "\n"
#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK
// cmds modifying text[]
int save_argc; // how many file names on cmd line
int cmdcnt; // repetition count
unsigned rows, columns; // the terminal screen is this size
+#if ENABLE_FEATURE_VI_ASK_TERMINAL
+ int get_rowcol_error;
+#endif
int crow, ccol; // cursor is on Crow x Ccol
int offset; // chars scrolled off the screen to the left
int have_status_msg; // is default edit status needed?
}
#if ENABLE_FEATURE_VI_WIN_RESIZE
-static void query_screen_dimensions(void)
+static int query_screen_dimensions(void)
{
- get_terminal_width_height(STDIN_FILENO, &columns, &rows);
+ int err = get_terminal_width_height(STDIN_FILENO, &columns, &rows);
if (rows > MAX_SCR_ROWS)
rows = MAX_SCR_ROWS;
if (columns > MAX_SCR_COLS)
columns = MAX_SCR_COLS;
+ return err;
}
#else
-# define query_screen_dimensions() ((void)0)
+# define query_screen_dimensions() (0)
#endif
static void edit_file(char *fn)
rows = 24;
columns = 80;
size = 0;
- query_screen_dimensions();
+ IF_FEATURE_VI_ASK_TERMINAL(G.get_rowcol_error =) query_screen_dimensions();
+#if ENABLE_FEATURE_VI_ASK_TERMINAL
+ if (G.get_rowcol_error /* TODO? && no input on stdin */) {
+ uint64_t k;
+ write1("\033[999;999H" "\033[6n");
+ fflush_all();
+ k = read_key(STDIN_FILENO, readbuffer, /*timeout_ms:*/ 100);
+ if ((int32_t)k == KEYCODE_CURSOR_POS) {
+ uint32_t rc = (k >> 32);
+ columns = (rc & 0x7fff);
+ if (columns > MAX_SCR_COLS)
+ columns = MAX_SCR_COLS;
+ rows = ((rc >> 16) & 0x7fff);
+ if (rows > MAX_SCR_ROWS)
+ rows = MAX_SCR_ROWS;
+ }
+ }
+#endif
new_screen(rows, columns); // get memory for virtual screen
init_text_buffer(fn);
//
if (!buf[0])
- goto vc1;
+ goto ret;
if (*buf == ':')
buf++; // move past the ':'
// don't edit, if the current file has been modified
if (file_modified && !useforce) {
status_line_bold("No write since last change (:edit! overrides)");
- goto vc1;
+ goto ret;
}
if (args[0]) {
// the user supplied a file name
} else {
// no user file name, no current name- punt
status_line_bold("No current filename");
- goto vc1;
+ goto ret;
}
if (init_text_buffer(fn) < 0)
- goto vc1;
+ goto ret;
#if ENABLE_FEATURE_VI_YANKMARK
if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) {
} else if (strncmp(cmd, "file", i) == 0) { // what File is this
if (b != -1 || e != -1) {
status_line_bold("No address allowed on this command");
- goto vc1;
+ goto ret;
}
if (args[0]) {
// user wants a new filename
if (c_is_no_print)
standout_end();
}
-#if ENABLE_FEATURE_VI_SET
- vc2:
-#endif
Hit_Return();
- } else if (strncmp(cmd, "quit", i) == 0 // Quit
+ } else if (strncmp(cmd, "quit", i) == 0 // quit
|| strncmp(cmd, "next", i) == 0 // edit next file
) {
int n;
optind = save_argc;
}
editing = 0;
- goto vc1;
+ goto ret;
}
// don't exit if the file been modified
if (file_modified) {
status_line_bold("No write since last change (:%s! overrides)",
(*cmd == 'q' ? "quit" : "next"));
- goto vc1;
+ goto ret;
}
// are there other file to edit
n = save_argc - optind - 1;
if (*cmd == 'q' && n > 0) {
status_line_bold("%d more file(s) to edit", n);
- goto vc1;
+ goto ret;
}
if (*cmd == 'n' && n <= 0) {
status_line_bold("No more files to edit");
- goto vc1;
+ goto ret;
}
editing = 0;
} else if (strncmp(cmd, "read", i) == 0) { // read file into text[]
fn = args;
if (!fn[0]) {
status_line_bold("No filename given");
- goto vc1;
+ goto ret;
}
if (b < 0) { // no addr given- use defaults
q = begin_line(dot); // assume "dot"
q = text + ofs;
}
if (ch < 0)
- goto vc1; // nothing was inserted
+ goto ret; // nothing was inserted
// how many lines in text[]?
li = count_lines(q, q + ch - 1);
status_line("\"%s\""
// only blank is regarded as args delmiter. What about tab '\t' ?
if (!args[0] || strcasecmp(args, "all") == 0) {
// print out values of all options
- go_bottom_and_clear_to_eol();
- printf("----------------------------------------\r\n");
#if ENABLE_FEATURE_VI_SETOPTS
- if (!autoindent)
- printf("no");
- printf("autoindent ");
- if (!err_method)
- printf("no");
- printf("flash ");
- if (!ignorecase)
- printf("no");
- printf("ignorecase ");
- if (!showmatch)
- printf("no");
- printf("showmatch ");
- printf("tabstop=%d ", tabstop);
-#endif
- printf("\r\n");
- goto vc2;
+ status_line_bold(
+ "%sautoindent "
+ "%sflash "
+ "%signorecase "
+ "%sshowmatch "
+ "tabstop=%u",
+ autoindent ? "" : "no",
+ err_method ? "" : "no",
+ ignorecase ? "" : "no",
+ showmatch ? "" : "no",
+ tabstop
+ );
+#endif
+ goto ret;
}
#if ENABLE_FEATURE_VI_SETOPTS
argp = args;
if (strncmp(argp, "no", 2) == 0)
i = 2; // ":set noautoindent"
setops(argp, "autoindent ", i, "ai", VI_AUTOINDENT);
- setops(argp, "flash ", i, "fl", VI_ERR_METHOD);
+ setops(argp, "flash " , i, "fl", VI_ERR_METHOD);
setops(argp, "ignorecase ", i, "ic", VI_IGNORECASE);
- setops(argp, "showmatch ", i, "ic", VI_SHOWMATCH);
- /* tabstopXXXX */
- if (strncmp(argp + i, "tabstop=%d ", 7) == 0) {
- sscanf(strchr(argp + i, '='), "tabstop=%d" + 7, &ch);
- if (ch > 0 && ch <= MAX_TABSTOP)
- tabstop = ch;
+ setops(argp, "showmatch " , i, "sm", VI_SHOWMATCH );
+ if (strncmp(argp + i, "tabstop=", 8) == 0) {
+ int t = 0;
+ sscanf(argp + i+8, "%u", &t);
+ if (t > 0 && t <= MAX_TABSTOP)
+ tabstop = t;
}
- while (*argp && *argp != ' ')
- argp++; // skip to arg delimiter (i.e. blank)
- while (*argp && *argp == ' ')
- argp++; // skip all delimiting blanks
+ argp = skip_non_whitespace(argp);
+ argp = skip_whitespace(argp);
}
#endif /* FEATURE_VI_SETOPTS */
#endif /* FEATURE_VI_SET */
#if ENABLE_FEATURE_VI_READONLY
if (readonly_mode && !useforce) {
status_line_bold("\"%s\" File is read only", fn);
- goto vc3;
+ goto ret;
}
#endif
// how many lines in text[]?
editing = 0;
}
}
-#if ENABLE_FEATURE_VI_READONLY
- vc3:;
-#endif
#if ENABLE_FEATURE_VI_YANKMARK
} else if (strncmp(cmd, "yank", i) == 0) { // yank lines
if (b < 0) { // no addr given- use defaults
// cmd unknown
not_implemented(cmd);
}
- vc1:
+ ret:
dot = bound_dot(dot); // make sure "dot" is valid
return;
#if ENABLE_FEATURE_VI_SEARCH
status_line_bold("No current filename");
return -2;
}
- charcnt = 0;
/* By popular request we do not open file with O_TRUNC,
* but instead ftruncate() it _after_ successful write.
* Might reduce amount of data lost on power fail etc.
int li, changed;
char *tp, *sp; // pointer into text[] and screen[]
- if (ENABLE_FEATURE_VI_WIN_RESIZE) {
+ if (ENABLE_FEATURE_VI_WIN_RESIZE IF_FEATURE_VI_ASK_TERMINAL(&& !G.get_rowcol_error) ) {
unsigned c = columns, r = rows;
query_screen_dimensions();
full_screen |= (c - columns) | (r - rows);