Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <ctype.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <locale.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <sys/ioctl.h>
- #include <sys/types.h>
- #include <termios.h>
- #include <unistd.h>
- #define MIN(a, b) ({ \
- __auto_type _a = (a); \
- __auto_type _b = (b); \
- _a < _b ? _a : _b; \
- })
- #define CTRL_KEY(k) ((k) & 0x1f)
- enum {
- KEY_BACKSPACE = 0x7f,
- KEY_LEFT = 0400,
- KEY_RIGHT,
- KEY_UP,
- KEY_DOWN,
- KEY_DEL,
- KEY_HOME,
- KEY_END,
- KEY_PAGEUP,
- KEY_PAGEDN,
- };
- struct termios orig_term;
- int term_lines;
- int term_cols;
- int term_tabsize = 8;
- struct line {
- int indent;
- char *text;
- size_t ntext;
- };
- struct buffer {
- struct line *lines;
- size_t nlines;
- size_t nbytes;
- };
- struct buffer buf;
- int view_width, view_height;
- size_t v_scroll;
- int line_append(struct line *line, char ch)
- {
- char *newtext;
- if (line->ntext == 0 && isblank(ch)) {
- line->indent += ch == ' ' ? 1 : 8;
- return 0;
- }
- newtext = realloc(line->text, sizeof(*line->text) * (line->ntext + 1));
- if (newtext == NULL)
- return -1;
- line->text = newtext;
- line->text[line->ntext++] = ch;
- return 0;
- }
- struct line *buf_newline(void)
- {
- struct line *newlines;
- newlines = realloc(buf.lines, sizeof(*buf.lines) * (buf.nlines + 1));
- if (newlines == NULL)
- return NULL;
- buf.lines = newlines;
- newlines += buf.nlines;
- memset(newlines, 0, sizeof(*newlines));
- buf.nlines++;
- return newlines;
- }
- int buf_read_file(const char *file)
- {
- int fd;
- char b[1024];
- struct line *line;
- ssize_t r;
- if ((fd = open(file, O_RDONLY)) < 0)
- return -1;
- buf.nlines = 0;
- buf.nbytes = 0;
- if ((line = buf_newline()) == NULL) {
- close(fd);
- return -1;
- }
- while ((r = read(fd, b, sizeof(b))) > 0)
- for(const char *p = b; r; r--, p++) {
- if (*p == '\n' && ((line = buf_newline()) == NULL))
- goto sudden_out_of_mem;
- if (*p != '\n' && line_append(line, *p) < 0)
- goto sudden_out_of_mem;
- buf.nbytes++;
- }
- /* fall through */
- sudden_out_of_mem:
- close(fd);
- return 0;
- }
- void handle_char(int c)
- {
- switch (c) {
- /*case KEY_RESIZE:
- view_width = term_cols;
- view_height = MIN((size_t) (term_lines - 1), buf.nlines);
- break;*/
- case KEY_DOWN:
- case 'j':
- if (v_scroll == buf.nlines - view_height)
- break;
- v_scroll++;
- break;
- case KEY_UP:
- case 'k':
- if (v_scroll == 0)
- break;
- v_scroll--;
- break;
- case KEY_HOME:
- case 'g':
- v_scroll = 0;
- break;
- case KEY_END:
- case 'G':
- v_scroll = buf.nlines - view_height;
- break;
- }
- }
- int enable_raw_mode(void)
- {
- struct termios raw;
- if (tcgetattr(STDIN_FILENO, &orig_term) == -1)
- return -1;
- raw = orig_term;
- raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
- raw.c_oflag &= ~(OPOST);
- raw.c_cflag |= CS8;
- raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
- raw.c_cc[VMIN] = 1;
- raw.c_cc[VTIME] = 0;
- /* For non blocking */
- //raw.c_cc[VMIN] = 0;
- //raw.c_cc[VTIME] = 1;
- if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1)
- return -1;
- return 0;
- }
- int get_window_size(void)
- {
- struct winsize ws;
- if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1)
- return 0;
- term_lines = ws.ws_row;
- term_cols = ws.ws_col;
- return 0;
- }
- int get_key(void)
- {
- int c;
- if ((c = getchar()) != 0x1b)
- return c;
- if ((c = getchar()) == '[') {
- c = getchar();
- if (isdigit(c)) {
- c = getchar();
- if (c == '~') {
- switch (c) {
- case '1': return KEY_HOME;
- case '3': return KEY_DEL;
- case '4': return KEY_END;
- case '5': return KEY_PAGEUP;
- case '6': return KEY_PAGEDN;
- case '7': return KEY_HOME;
- case '8': return KEY_END;
- }
- }
- } else {
- switch (c) {
- case 'A': return KEY_UP;
- case 'B': return KEY_DOWN;
- case 'C': return KEY_RIGHT;
- case 'D': return KEY_LEFT;
- case 'H': return KEY_HOME;
- case 'F': return KEY_END;
- }
- }
- } else if (c == 'O') {
- c = getchar();
- switch (c) {
- case 'H': return KEY_HOME;
- case 'F': return KEY_END;
- }
- }
- return -1;
- }
- int main(int argc, char **argv)
- {
- if (argc < 2) {
- fprintf(stderr, "usage: %s <file name>\n", argv[0]);
- return -1;
- }
- setlocale(LC_ALL, "");
- /* make stdout unbuffered */
- setbuf(stdout, NULL);
- if (enable_raw_mode() == -1) {
- fprintf(stderr, "couldn't enabel raw mode\n");
- return -1;
- }
- if (get_window_size() == -1) {
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_term);
- fprintf(stderr, "unable to get terminal size\n");
- return -1;
- }
- if (buf_read_file(argv[1]) == -1) {
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_term);
- fprintf(stderr, "error reading file '%s'\n", argv[1]);
- return -1;
- }
- printf("\x1b[?25l"); /* hide the cursor */
- /* Initial size */
- view_width = term_cols;
- view_height = MIN((size_t) (term_lines - 1), buf.nlines);
- /* Main loop */
- while (1) {
- printf("\x1b[0;0H");
- for (size_t i = 0, e = MIN((size_t) view_height, buf.nlines);
- i < e; i++) {
- const struct line *const line = buf.lines +
- v_scroll + i;
- write(STDIN_FILENO, line->text, line->ntext);
- printf("\x1b[K\r\n");
- }
- printf("\x1b[7m"); /* reverse video */
- printf("%4zu-%4zu/%4zu (%3d%%) %zub (view=%dx%d) (term=%dx%d)",
- v_scroll + 1, v_scroll + view_height,
- buf.nlines,
- buf.nlines == (size_t) view_height ? 100 :
- (int) (100 *
- v_scroll / (buf.nlines - view_height)),
- buf.nbytes,
- view_width, view_height,
- term_cols, term_lines);
- printf("\x1b[0m"); /* reset attributes */
- const int c = get_key();
- if (c == CTRL_KEY('C') || c == 'q')
- break;
- handle_char(c);
- }
- for (size_t i = 0; i < buf.nlines; i++)
- free(buf.lines[i].text);
- free(buf.lines);
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_term);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement