ref: 9bc180134a6a2c2943f33f84a0d1b7aa9bf0072d
dir: /os_plan9.c/
/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * os_plan9.c * * Plan 9 system-dependent routines. */ #include <signal.h> #include <setjmp.h> #include <fcntl.h> #include <lib9.h> #include <draw.h> #include <keyboard.h> #include <event.h> #include <plumb.h> #include "vim.h" /* Vim defines Display. We need it for libdraw. */ #undef Display /* We need to access the native Plan 9 alarm() since * it takes milliseconds rather than seconds. */ extern int _ALARM(unsigned long); extern int _SLEEP(long); enum { /* Text modes are in sync with term.c */ TMODE_NORMAL = 0, TMODE_REVERSE = 1, TMODE_BOLD = 2, NCOLORS = 256 }; static int scr_inited; static Point fontsize; static Point shellsize; static Rectangle scrollregion; static int currow; /* TODO use a Point */ static int curcol; static Image *cursorsave; static Image *colortab[NCOLORS]; static Image *fgcolor; static Image *bgcolor; static Font *normalfont; static Font *boldfont; static Font *curfont; static int curmode; /* TODO remove this, use cterm_normal_fg_color instead for comparing */ static int plumbkey; static int done; /* Timeouts are handled using alarm() and a signal handler. * When an alarm happens during a syscall, the syscall is * interrupted. We use setjmp() to handle control flow from * interrupted library functions. */ static int interruptable; static jmp_buf timeoutjmpbuf; static void err9(char *msg) { char errs[256]; /* TODO */ errstr(errs, sizeof errs); fprintf(stderr, "%s: %s\n", msg, errs); exit(1); } /* Error handler for libdraw */ static void derr(Display*, char *msg) { if (interruptable && strcmp(msg, "eof on event pipe") == 0) { longjmp(timeoutjmpbuf, 1); } err9(msg); } static void drain_plumb_events(void) { Event e; Plumbmsg *m; char *addr; int l = ECMD_ONE; while(ecanread(plumbkey)){ eread(plumbkey, &e); m = e.v; addr = plumblookup(m->attr, "addr"); if(addr) l = atoi(addr); do_ecmd(0, (char_u*)m->data, NULL, NULL, (linenr_T)l, ECMD_HIDE); shell_resized(); } } static void start_plumber_thread(void) { switch (rfork(RFPROC|RFMEM)){ case -1: fprintf(stderr, "rfork failed\n"); return; case 0: while(!done){ drain_plumb_events(); _SLEEP(100); } exit(0); default: break; } } int mch_has_wildcard(char_u *p) { for (; *p; mb_ptr_adv(p)) { if (*p == '\\' && p[1] != NUL) { ++p; } else if (vim_strchr((char_u *)"*?[{`'$", *p) != NULL || (*p == '~' && p[1] != NUL)) { return TRUE; } } return FALSE; } int mch_has_exp_wildcard(char_u *p) { for (; *p; mb_ptr_adv(p)) { if (*p == '\\' && p[1] != NUL) ++p; else if (vim_strchr((char_u *) "*?[{'", *p) != NULL) return TRUE; } return FALSE; } int mch_expandpath(garray_T *gap, char_u *pat, int flags) { return unix_expandpath(gap, pat, 0, flags, FALSE); } int mch_isdir(char_u *name) { struct stat st; if (stat((char*)name, &st) != 0) { return FALSE; } return S_ISDIR(st.st_mode) ? TRUE : FALSE; } static int executable_file(char_u *name) { struct stat st; if (stat((char *)name, &st)) return 0; return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0; } int mch_isFullName(char_u *fname) { return fname[0] == '/' || fname[0] == '#'; } int mch_can_exe(char_u *name) { char_u *buf; char_u *p, *e; int retval; /* If it's an absolute or relative path don't need to use $path. */ if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/')))) return executable_file(name); p = (char_u *)getenv("path"); if (p == NULL || *p == NUL) return -1; buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2)); if (buf == NULL) return -1; /* * Walk through all entries in $PATH to check if "name" exists there and * is an executable file. */ for (;;) { e = (char_u *)strchr((char *)p, '\01'); if (e == NULL) e = p + STRLEN(p); if (e - p <= 1) /* empty entry means current dir */ STRCPY(buf, "./"); else { vim_strncpy(buf, p, e - p); add_pathsep(buf); } STRCAT(buf, name); retval = executable_file(buf); if (retval == 1) break; if (*e != '\01') break; p = e + 1; } vim_free(buf); return retval; } int mch_dirname(char_u *buf, int len) { return (getcwd((char*)buf, len) ? OK : FAIL); } long mch_getperm(char_u *name) { struct stat st; if (stat((char*)name, &st) < 0) { return -1; } return st.st_mode; } int mch_setperm(char_u *name, long perm) { return chmod((char*)name, (mode_t)perm) == 0 ? OK : FAIL; } int mch_remove(char_u *name) { return remove((char*)name); } void mch_hide(char_u*) { /* Do nothing */ } /* getuser() and sysname() can be implemented using this. */ static int read_value_from_file(char *fname, char_u *s, int len) { int fd; int n; fd = open(fname, O_RDONLY); if (fd < 0) { vim_strncpy(s, (char_u*)"none", len - 1); return FAIL; } n = read(fd, s, len - 1); if (n <= 0) { vim_strncpy(s, (char_u*)"none", len - 1); } else { s[n] = '\0'; } close(fd); return (n > 0) ? OK : FAIL; } int mch_get_user_name(char_u *s, int len) { return read_value_from_file("/dev/user", s, len); } void mch_get_host_name(char_u *s, int len) { read_value_from_file("/dev/sysname", s, len); } void mch_settmode(int) { /* Do nothing */ } int mch_screenmode(char_u*) { /* Always fail */ EMSG(_(e_screenmode)); return FAIL; } static void scr_stamp_cursor(void) { if (cursorsave) { draw(cursorsave, Rect(0, 0, fontsize.x, fontsize.y), screen, nil, Pt(screen->clipr.min.x + curcol * fontsize.x, screen->clipr.min.y + currow * fontsize.y)); drawop(screen, Rect(screen->clipr.min.x + curcol * fontsize.x, screen->clipr.min.y + currow * fontsize.y, screen->clipr.min.x + (curcol + 1) * fontsize.x, screen->clipr.min.y + (currow + 1) * fontsize.y), colortab[cterm_normal_fg_color - 1], cursorsave, ZP, SoverD); } } static void scr_unstamp_cursor(void) { if (cursorsave) { Rectangle r; r = Rect(screen->clipr.min.x + curcol * fontsize.x, screen->clipr.min.y + currow * fontsize.y, screen->clipr.min.x + (curcol + 1) * fontsize.x, screen->clipr.min.y + (currow + 1) * fontsize.y); draw(screen, r, cursorsave, nil, ZP); } } static void scr_pos(int row, int col) { currow = row; curcol = col; } static void scr_clear(void) { scr_pos(0, 0); draw(screen, screen->clipr, bgcolor, nil, ZP); draw(cursorsave, Rect(0, 0, fontsize.x, fontsize.y), bgcolor, nil, ZP); } static void scr_scroll_down(int nlines) { Rectangle r; Point pt; /* Copy up visible part of scroll region */ r = Rect(screen->clipr.min.x + scrollregion.min.x * fontsize.x, screen->clipr.min.y + scrollregion.min.y * fontsize.y, screen->clipr.min.x + scrollregion.max.x * fontsize.x, screen->clipr.min.y + (scrollregion.max.y - nlines) * fontsize.y); pt = Pt(screen->clipr.min.x + scrollregion.min.x * fontsize.x, screen->clipr.min.y + (scrollregion.min.y + nlines) * fontsize.y); draw(screen, r, screen, nil, pt); /* Clear newly exposed part of scroll region */ r.min.y = r.max.y; r.max.y = screen->clipr.min.y + scrollregion.max.y * fontsize.y; draw(screen, r, bgcolor, nil, ZP); } static void scr_scroll_up(int nlines) { Rectangle r; Point pt; /* Copy down visible part of scroll region */ r = Rect(screen->clipr.min.x + scrollregion.min.x * fontsize.x, screen->clipr.min.y + (scrollregion.min.y + nlines) * fontsize.y, screen->clipr.min.x + scrollregion.max.x * fontsize.x, screen->clipr.min.y + scrollregion.max.y * fontsize.y); pt = Pt(screen->clipr.min.x + scrollregion.min.x * fontsize.x, screen->clipr.min.y + scrollregion.min.y * fontsize.y); draw(screen, r, screen, nil, pt); /* Clear newly exposed part of scroll region */ r.max.y = r.min.y; r.min.y = screen->clipr.min.y + scrollregion.min.y * fontsize.y; draw(screen, r, bgcolor, nil, ZP); } static void scr_set_color(Image **cp, int c) { if (c >= 0 && c < NCOLORS) { *cp = colortab[c]; } } void mch_set_normal_colors(void) { char_u *p; int n; if (cterm_normal_fg_color == 0) { cterm_normal_fg_color = 1; } if (cterm_normal_bg_color == 0) { cterm_normal_bg_color = 16; } if (T_ME[0] == ESC && T_ME[1] == '|') { p = T_ME + 2; n = getdigits(&p); if (*p == 'm' && n > 0) { cterm_normal_fg_color = (n & 0xf) + 1; cterm_normal_bg_color = ((n >> 4) & 0xf) + 1; } } scr_set_color(&bgcolor, cterm_normal_bg_color - 1); scr_set_color(&fgcolor, cterm_normal_fg_color - 1); } static void scr_tmode(int mode) { Image *tmp; if ((curmode & TMODE_REVERSE) != (mode & TMODE_REVERSE)) { tmp = fgcolor; fgcolor = bgcolor; bgcolor = tmp; } if (mode & TMODE_BOLD) { curfont = boldfont; } else { curfont = normalfont; } if (mode == TMODE_NORMAL) { scr_set_color(&bgcolor, cterm_normal_bg_color - 1); scr_set_color(&fgcolor, cterm_normal_fg_color - 1); } curmode = mode; } /* Read a number and return bytes consumed. */ static int scr_escape_number(char *p, int len, int *n) { int num; int chlen; if (len == 0) { return -1; } num = 0; chlen = 0; while (len && isdigit(*p)) { num = num * 10 + (*p - '0'); p++; len--; chlen++; } *n = num; return chlen; } /* Handle escape sequence and return number of bytes consumed. */ static int scr_escape_sequence(char *p, int len) { int nlines; int n1; int n2; int i; int chlen; if (len == 0) { return 0; } chlen = 1; switch (*p) { case 'J': /* clear screen */ scr_clear(); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n1 = -1; n2 = -1; /* First number */ i = scr_escape_number(p, len, &n1); if (i == -1) { /* TODO */ fprintf(stderr, "scr_escape_sequence: escape at end of string\n"); exit(1); } p += i; len -= i; chlen += i; /* Optional second number */ if (len && *p == ';') { p += 1; len -= 1; chlen += 1; i = scr_escape_number(p, len, &n2); if (i == -1) { /* TODO */ fprintf(stderr, "scr_escape_sequence: missing second number\n"); exit(1); } p += i; len -= i; chlen += i; } if (len == 0) { /* TODO */ fprintf(stderr, "scr_escape_sequence: early end of escape sequence\n"); trash_input_buf(); return 0; } switch (*p) { case 'b': /* background color */ scr_set_color(&bgcolor, n1); break; case 'f': /* foreground color */ scr_set_color(&fgcolor, n1); break; case 'H': /* cursor motion */ scr_pos(n1, n2); break; case 'm': /* mode */ scr_tmode(n1); break; case 'R': /* scroll region */ scrollregion.min.y = n1; scrollregion.max.y = n2 + 1; break; case 'V': /* scroll region vertical */ scrollregion.min.x = n1; scrollregion.max.x = n2 + 1; break; default: /* TODO */ fprintf(stderr, "scr_escape_sequence: unimplemented (p=%c)\n", *p); exit(1); } break; case 'K': /* clear to end of line */ draw(screen, Rect(screen->clipr.min.x + curcol * fontsize.x, screen->clipr.min.y + currow * fontsize.y, screen->clipr.max.x, screen->clipr.min.y + (currow + 1) * fontsize.y), bgcolor, nil, ZP); break; case 'L': /* add new blank line */ p++; nlines = 1; while (len >= 3 && p[0] == '\x1b' && p[1] == '[' && p[2] == 'L') { nlines++; len -= 3; p += 3; chlen += 3; } /* TODO what if nlines >= scroll region size */ scr_scroll_up(nlines); break; default: /* TODO */ fprintf(stderr, "scr_escape_sequence: unhandled sequence (p=%c)\n", *p); exit(1); } return chlen; } /* Handle special characters. */ static int write_special(char *p, int len) { int n; int nbytes; if (len == 0) { return 0; } nbytes = 0; while (len > 0) { switch (*p) { case '\a': /* Bell */ /* There is no bell on Plan 9. */ break; case '\b': /* Backspace */ if (curcol > scrollregion.min.x) { scr_pos(currow, curcol - 1); } else if (currow > scrollregion.min.y) { scr_pos(currow - 1, scrollregion.max.x - 1); } break; case '\n': /* New line */ for (n = 0; n < len && *p == '\n'; n++) { p++; } if (currow + n >= scrollregion.max.y) { scr_scroll_down(currow + n - scrollregion.max.y + 1); scr_pos(scrollregion.max.y - 1, scrollregion.min.x); } else { scr_pos(currow + n, scrollregion.min.x); } len -= n; nbytes += n; continue; /* process next character */ case '\r': /* Carriage return */ curcol = scrollregion.min.x; break; case '\x1b': /* Escape sequences */ if (len > 1 && p[1] == '[') { n = 2; n += scr_escape_sequence(p + 2, len - 2); p += n; len -= n; nbytes += n; continue; /* process next character */ } break; default: /* Normal character */ return nbytes; } p++; len--; nbytes++; } return nbytes; } /* Draw normal characters. */ static int write_str(char *p, int len) { int nbytes, n, m, rn, rl; Rune r; if (len == 0) { return 0; } for (nbytes = 0; nbytes < len && p[nbytes] != '\a' && p[nbytes] != '\b' && p[nbytes] != '\n' && p[nbytes] != '\r' && p[nbytes] != '\x1b'; len--, nbytes++) ; n = nbytes; rl = 0; while (n > 0) { rn = chartorune(&r, p); rl += rn; m = (curcol + 1 >= scrollregion.max.x) ? scrollregion.max.x - curcol : 1; if (m == 0) { break; } runestringnbg(screen, Pt(screen->clipr.min.x + curcol * fontsize.x, screen->clipr.min.y + currow * fontsize.y), fgcolor, ZP, curfont, &r, 1, bgcolor, ZP); curcol += m; if (curcol == scrollregion.max.x) { curcol = scrollregion.min.x; if (currow == scrollregion.max.y - 1) { scr_scroll_down(1); } else { currow++; } } p += rn; n -= rn; } return rl; } void mch_write(char_u *p, int len) { int slen; scr_unstamp_cursor(); while (len > 0) { /* Handle special characters. */ slen = write_special((char*)p, len); p += slen; len -= slen; /* Write as many normal characters as possible. */ slen = write_str((char*)p, len); p += slen; len -= slen; } scr_stamp_cursor(); flushimage(display, 1); } static void sigalrm(int, char*, void*) { /* Do nothing */ } static void send_mouse_event(int e, int x, int y) { char_u string[8]; int row; int col; int n; n = 0; row = y/fontsize.y; col = x/fontsize.x; string[n++] = CSI; string[n++] = 'M'; string[n++] = e; string[n++] = (char_u)(col + ' ' + 1); string[n++] = (char_u)(row + ' ' + 1); add_to_input_buf(string, n); } /* Don't allow mouse events to accumulate. */ static void process_mouse_events(void) { static int last_button = 0; Mouse m; Point pt; int code; while (ecanmouse()) { m = emouse(); pt = subpt(m.xy, screen->r.min); if(last_button) { if(m.buttons) { code = MOUSE_DRAG; } else { code = MOUSE_RELEASE; last_button = 0; } } else { if(m.buttons&1) { code = MOUSE_LEFT; last_button = 1; } else if(m.buttons&2) { code = MOUSE_MIDDLE; last_button = 2; } else if(m.buttons&4) { code = MOUSE_RIGHT; last_button = 4; } else if(m.buttons&8) { code = MOUSEWHEEL_LOW; last_button = 8; } else if(m.buttons&16) { code = MOUSEWHEEL_LOW|1; last_button = 16; } else { continue; } code |= 0x20; } send_mouse_event(code, pt.x, pt.y); } } int RealWaitForChar(int, long msec, int*) { Rune rune; char utf[UTFmax]; int len; if (msec == 0 && !ecankbd() && !ecanmouse()) { return 0; } if (msec > 0) { if (setjmp(timeoutjmpbuf)) { /* We arrive here if the alarm occurred and a library * function called drawerror() due to an interrupted * syscall. */ _ALARM(0); interruptable = 0; return 0; } interruptable = 1; _ALARM((unsigned long)msec); } if(ecankbd()) { /* TODO garbage collect */ rune = ekbd(); if (msec > 0) { _ALARM(0); interruptable = 0; } if (rune == Ctrl_C && ctrl_c_interrupts) { got_int = TRUE; return 0; } if(rune == '\n'){ utf[0] = CAR; len = 1; }else len = runetochar(utf, &rune); add_to_input_buf((char_u*)utf, len); /* TODO escape K_SPECIAL? */ return len > 0; } else if(ecanmouse()) { process_mouse_events(); } return 0; } int mch_inchar(char_u *buf, int maxlen, long msec, int) { if (vim_is_input_buf_empty() && RealWaitForChar(0, msec, NULL) == 0) { return 0; } return read_from_input_buf(buf, maxlen); } int mch_char_avail(void) { return ecankbd() || ecanmouse(); } void mch_delay(long msec, int ignoreinput) { if (ignoreinput) { sleep(msec / 1000); } else { RealWaitForChar(0, msec, NULL); } } int mch_nodetype(char_u *name) { struct stat st; if (stat((char*)name, &st) < 0) { return NODE_NORMAL; } if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) { return NODE_NORMAL; } return NODE_WRITABLE; } int mch_FullName(char_u *fname, char_u *buf, int len, int force) { int l; char_u olddir[MAXPATHL]; char_u *p; int retval = OK; /* expand it if forced or not an absolute path */ if (force || !mch_isFullName(fname)) { /* * If the file name has a path, change to that directory for a moment, * and then do the getwd() (and get back to where we were). * This will get the correct path name with "../" things. */ if ((p = vim_strrchr(fname, '/')) != NULL) { /* Only change directory when we are sure we can return to where * we are now. After doing "su" chdir(".") might not work. */ if ( (mch_dirname(olddir, MAXPATHL) == FAIL || mch_chdir((char *)olddir) != 0)) { p = NULL; /* can't get current dir: don't chdir */ retval = FAIL; } else { /* The directory is copied into buf[], to be able to remove * the file name without changing it (could be a string in * read-only memory) */ if (p - fname >= len) retval = FAIL; else { vim_strncpy(buf, fname, p - fname); if (mch_chdir((char *)buf)) retval = FAIL; else fname = p + 1; *buf = NUL; } } } if (mch_dirname(buf, len) == FAIL) { retval = FAIL; *buf = NUL; } if (p != NULL) { l = mch_chdir((char *)olddir); if (l != 0) EMSG(_(e_prev_dir)); } l = STRLEN(buf); if (l >= len) retval = FAIL; else { if (l > 0 && buf[l - 1] != '/' && *fname != NUL && STRCMP(fname, ".") != 0) STRCAT(buf, "/"); } } /* Catch file names which are too long. */ if (retval == FAIL || STRLEN(buf) + STRLEN(fname) >= len) return FAIL; /* Do not append ".", "/dir/." is equal to "/dir". */ if (STRCMP(fname, ".") != 0) STRCAT(buf, fname); return OK; } long mch_get_pid(void) { return (long)getpid(); } int mch_input_isatty(void) { return isatty(0) ? TRUE : FALSE; } int mch_setenv(char *var, char *value, int x) { char buf[100]; int fd; int len; snprintf(buf, sizeof buf, "/env/%s", var); /* Check for overwrite */ if (!x) { struct stat st; if (stat(buf, &st) == 0) { return -1; } } /* Write the value */ fd = creat(buf, 0666); if (fd < 0) { return -1; } len = strlen(value); if (write(fd, value, len) != len) { close(fd); return -1; } close(fd); return 0; } void mch_suspend(void) { suspend_shell(); } static void update_shellsize(void) { shellsize = Pt((screen->clipr.max.x - screen->clipr.min.x) / fontsize.x, (screen->clipr.max.y - screen->clipr.min.y) / fontsize.y); } int mch_get_shellsize(void) { update_shellsize(); Rows = shellsize.y; Columns = shellsize.x; scrollregion.min.x = 0; scrollregion.min.y = 0; scrollregion.max.x = shellsize.x; scrollregion.max.y = shellsize.y; return OK; } void mch_set_shellsize(void) { /* Do nothing */ } void mch_new_shellsize(void) { /* Do nothing */ } void mch_breakcheck(void) { if (scr_inited) { /* Read into input buffer and check for Ctrl-C. */ RealWaitForChar(0, 0, NULL); } } /* Called by libevent whenever a resize event occurs. */ void eresized(int renew) { if (renew) { if (getwindow(display, Refnone) < 0) { err9("resize failed"); } } shell_resized(); } static void init_colors(void) { int i; ulong colors[] = { /* gruvbox dark theme */ 0x282828ff, 0xcc241dff, 0x98971aff, 0xd79921ff, 0x458588ff, 0xb16286ff, 0x689d6aff, 0xa89984ff, 0x928374ff, 0xfb4934ff, 0xb8bb26ff, 0xfabd2fff, 0x83a598ff, 0xd3869bff, 0x8ec07cff,0xebdbb2ff, }; for (i = 0; i < 16; i++) { colortab[i] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, colors[i]); if (colortab[i] == nil) { err9("allocimage failed"); } } colortab[24] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x076678ff); colortab[66] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x427b58ff); colortab[88] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x9d0006ff); colortab[96] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x8f3f71ff); colortab[100] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x79740eff); colortab[108] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x8ec07cff); colortab[109] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x83a598ff); colortab[130] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xaf3a03ff); colortab[136] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xb57614ff); colortab[142] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xb8bb26ff); colortab[167] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xfb4934ff); colortab[175] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xd3869bff); colortab[208] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xfe8019ff); colortab[214] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xfabd2fff); colortab[223] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xebdbb2ff); colortab[228] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xf2e5bcff); colortab[229] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xfbf1c7ff); colortab[230] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xf9f5d7ff); colortab[234] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x1d2021ff); colortab[235] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x282828ff); colortab[236] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x32302fff); colortab[237] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x3c3836ff); colortab[239] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x504945ff); colortab[241] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x665c54ff); colortab[243] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x7c6f64ff); colortab[244] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x928374ff); colortab[245] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x928374ff); colortab[246] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xa89984ff); colortab[248] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xbdae93ff); colortab[250] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xd5c4a1ff); mch_set_normal_colors(); } static void free_colors(void) { int i; bgcolor = nil; fgcolor = nil; for (i = 0; i < NCOLORS; i++) { freeimage(colortab[i]); colortab[i] = nil; } } static void init_fonts(void) { char *n; n = getenv("font"); if(n) normalfont = openfont(display, n); else normalfont = openfont(display, "/lib/font/bit/fixed/unicode.9x18.font"); if (normalfont == nil) { err9("openfont normal failed"); } boldfont = openfont(display, n ? n : "/lib/font/bit/fixed/unicode.9x18B.font"); if (boldfont == nil) { err9("openfont bold failed"); } curfont = normalfont; } static void free_fonts(void) { freefont(normalfont); freefont(boldfont); curfont = nil; } void mch_early_init(void) { rfork(RFENVG | RFNOTEG); } int mch_check_win(int, char**) { return OK; } static void scr_init(void) { if (initdraw(derr, nil, "Vim") == -1) { err9("initdraw failed"); } init_colors(); init_fonts(); fontsize = stringsize(curfont, "A"); cursorsave = allocimage(display, Rect(0, 0, fontsize.x, fontsize.y), screen->chan, 0, DBlack); mch_get_shellsize(); scr_clear(); scr_stamp_cursor(); flushimage(display, 1); /* Mouse events must be enabled to receive window resizes. */ einit(Emouse | Ekeyboard); plumbkey = eplumb(512, "edit"); start_plumber_thread(); scr_inited = TRUE; } void mch_init(void) { done = FALSE; signal(SIGALRM, sigalrm); scr_init(); /* * Force UTF-8 output no matter what the value of 'encoding' is. * did_set_string_option() in option.c prohibits changing 'termencoding' * to something else than UTF-8. */ set_option_value((char_u *)"termencoding", 0L, (char_u *)"utf-8", 0); #if defined(FEAT_CLIPBOARD) clip_init(TRUE); #endif } void mch_exit(int r) { done = TRUE; ml_close_all(TRUE); /* remove all memfiles */ /* libdraw shuts down automatically on exit */ exit(r); } #if defined(FEAT_TITLE) void mch_settitle(char_u *title, char_u *) { int fd; fd = open("/dev/label", O_WRONLY); if (fd < 0) { /* Not running under rio. */ return; } write(fd, (char*)title, strlen((char*)title)); close(fd); } void mch_restore_title(int) { /* No need to restore - libdraw does this automatically. */ } int mch_can_restore_title(void) { return TRUE; } int mch_can_restore_icon(void) { return FALSE; } #endif #if defined(FEAT_CLIPBOARD) int clip_mch_own_selection(VimClipboard*) { /* We never own the clipboard. */ return FAIL; } void clip_mch_lose_selection(VimClipboard*) { /* Do nothing */ } void clip_mch_request_selection(VimClipboard *cbd) { int fd; char_u *data; char_u *newdata; long_u len; /* used length */ long_u mlen; /* max allocated length */ ssize_t n; int type; fd = open("/dev/snarf", O_RDONLY); if (fd < 0) { /* Not running under rio. */ return; } n = 0; len = 0; mlen = 0; data = NULL; do { len += n; mlen += 4096; newdata = vim_realloc(data, mlen); if (!newdata) { n = -1; break; } data = newdata; n = read(fd, data, 4096); /* TODO breakcheck? */ } while (n == 4096); if (n >= 0) { len += n; type = memchr(data, '\n', len) ? MLINE : MCHAR; clip_yank_selection(type, data, len, cbd); } vim_free(data); close(fd); } void clip_mch_set_selection(VimClipboard *cbd) { char_u *data; long_u len; int type; int fd; fd = open("/dev/snarf", O_RDONLY); if (fd < 0) return; /* If the '*' register isn't already filled in, fill it in now. */ cbd->owned = TRUE; clip_get_selection(cbd); cbd->owned = FALSE; type = clip_convert_selection(&data, &len, cbd); if (type < 0) { return; } fd = open("/dev/snarf", O_WRONLY); if (fd >= 0) { write(fd, data, len); close(fd); } vim_free(data); } #endif #if defined(FEAT_MOUSE) void mch_setmouse(int) { /* Do nothing. Mouse needed for clipboard. */ } #endif int mch_call_shell(char_u *cmd, int options) { pid_t pid; int status; if(options & SHELL_COOKED) settmode(TMODE_COOK); pid = rfork(RFPROC|RFFDG|RFENVG|RFNOTEG); if(pid < 0) return -1; if(pid == 0){ if (cmd) execl("/bin/rc", "rc", "-c", cmd, NULL); else execl("/bin/rc", "rc", NULL); _exit(122); } waitpid(pid, &status, 0); return status; }