📄 shell.c
字号:
if (count || do_redraw) {/* we do a manual appending of the text for optimization purposes, instead of CRedrawTextbox */ w->text = (char *) pool_start (r->shell_pool); CPushFont ("editor", 0); w->numlines += strcountlines (w->text + w->textlength, 0, 2000000000, w->options & TEXTBOX_WRAP ? (w->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000); w->textlength = pool_length (r->shell_pool);/* only redraw if we crossed a newline */ if (strchr (w->text + w->textlength - count, '\n')) { CExpose (w->ident); if (w->winid != CGetFocus ()) if (w->numlines > w->firstline + (w->height / FONT_PIX_PER_LINE - 1)) CSetTextboxPos (w, TEXT_SET_LINE, w->numlines - (w->height / FONT_PIX_PER_LINE - 1)); } CPopFont (); } r->killme |= CChildExitted (r->shell_pid, 0); if (!count && r->killme) { pool_break (r->shell_pool); r->shell_pool = 0; CRemoveWatch (fd, shell_pool_update, WATCH_READING); close (fd); r->shell_pipe = -1; }}/* draws a textbox dialog for showing the shells output */static void shell_display_output (char *text, const char *heading, int (*select_line_callback) (CWidget *, XEvent *, CEvent *), char *name){ int i; if (!text) text = ""; i = find_shell (0, name, 0); if (i >= 0 && CIdent (nm (i, "shelldisplaytext", 0, 0))) { /* exists ? */ CWidget *w; w = CIdent (nm (i, "shelldisplaytext", "text", 0)); free (w->text); w->text = 0; CRedrawTextbox (nm (i, "shelldisplaytext", "text", 0), text, 0); CRedrawText (nm (i, "shelldisplaytext", "header", 0), heading); CFocus (CIdent (nm (i, "shelldisplaytext", "text", 0))); CRaiseWMWindow (nm (i, "shelldisplaytext", 0, 0)); } else { int x, y; Window win; CWidget *w; win = CDrawMainWindow (nm (i, "shelldisplaytext", 0, 0), heading); CGetHintPos (&x, &y); CPushFont ("editor", 0); running_shell[i].w = w = CDrawTextbox (nm (i, "shelldisplaytext", "text", 0), win, x, y, 80 * FONT_MEAN_WIDTH + 7, 25 * FONT_PIX_PER_LINE + 6, 0, 0, text, TEXTBOX_WRAP | TEXTBOX_NO_STRDUP);/* Toolhint */ CSetToolHint (nm (i, "shelldisplaytext", "text", 0), _ ("Double click on file:line type messages to goto the\nfile and line number. Note that the file will not\nauto-load unless there is a full path in the message.")); w->position |= POSITION_HEIGHT | POSITION_WIDTH; (CIdent (nm (i, "shelldisplaytext", "text", "vsc")))->position |= POSITION_HEIGHT | POSITION_RIGHT; CGetHintPos (0, &y); (CDrawPixmapButton (nm (i, "shelldisplaytext", "done", 0), win, 0, y, PIXMAP_BUTTON_TICK))->position = POSITION_BOTTOM | POSITION_CENTRE;/* Toolhint */ CSetToolHint (nm (i, "shelldisplaytext", "done", 0), _ ("Kill the running script")); CCentre (nm (i, "shelldisplaytext", "done", 0)); CSetSizeHintPos (nm (i, "shelldisplaytext", 0, 0)); CSetWindowResizable (nm (i, "shelldisplaytext", 0, 0), FONT_MEAN_WIDTH * 15, FONT_PIX_PER_LINE * 15, 1600, 1200); /* minimum and maximum sizes */ CPopFont (); CMapDialog (nm (i, "shelldisplaytext", 0, 0)); CAddCallback (nm (i, "shelldisplaytext", "text", 0), select_line_callback); CAddCallback (nm (i, "shelldisplaytext", "done", 0), display_file_callback); CFocus (CIdent (nm (i, "shelldisplaytext", "done", 0))); }}/* }}} dynamic display of shell output in a dialog box */static char *hme_i (char *h, int i){ static char s[MAX_PATH_LEN]; sprintf (s, "%s-%d", hme (h), i); return s;}/* returns non-zero on error */int execute_background_display_output (char *title, char *s, char *name){ char *argv[] = {0, 0}; pid_t p; int i; i = restart_shell (0, name, 0); argv[0] = hme_i (SCRIPT_FILE, i); savefile (argv[0], s, strlen (s), 0700); if ((p = triple_pipe_open (0, &running_shell[i].shell_pipe, 0, 1, argv[0], argv)) < 0) return 1; running_shell[i].shell_pid = p; if (!running_shell[i].shell_pool) { running_shell[i].shell_pool = pool_init (); pool_null (running_shell[i].shell_pool); } shell_display_output ((char *) pool_start (running_shell[i].shell_pool), title, goto_file_callback, name); CAddWatch (running_shell[i].shell_pipe, shell_pool_update, WATCH_READING, (void *) i); return 0;}/* Executes the shell in the background. The "Insert File" options will be ignored if this is called. */static int execute_background_shell (struct shell_cmd *s, char *script, char *name){ char *argv[] = {0, 0}; pid_t p = 0; int i; i = restart_shell (0, name, 0); argv[0] = hme_i (SCRIPT_FILE, i); savefile (argv[0], script, strlen (script), 0700); if (s->options & SHELL_OPTION_DISPLAY_STDOUT_CONTINUOUS) { if ((p = triple_pipe_open (0, &running_shell[i].shell_pipe, 0, (s->options & SHELL_OPTION_DISPLAY_STDERR_CONTINUOUS) ? 1 : 0, hme_i (SCRIPT_FILE, i), argv)) < 0) return 0; } else { if (!(s->options & SHELL_OPTION_DISPLAY_STDERR_CONTINUOUS)) { /* no output desired, just run in background */ switch (fork ()) { case 0:{ int nulldevice_wr, nulldevice_rd; nulldevice_wr = open ("/dev/null", O_WRONLY); nulldevice_rd = open ("/dev/null", O_RDONLY); close (0); dup (nulldevice_rd); close (1); dup (nulldevice_wr); close (2); dup (nulldevice_wr); set_signal_handlers_to_default (); execlp (argv[0], argv[0], 0); exit (0); /* should never reach */ } case -1: return 0; default: return 1; } } if ((p = triple_pipe_open (0, 0, &running_shell[i].shell_pipe, 0, hme_i (SCRIPT_FILE, i), argv)) < 0) return 0; } running_shell[i].shell_pid = p; if (!running_shell[i].shell_pool) { running_shell[i].shell_pool = pool_init (); pool_null (running_shell[i].shell_pool); } shell_display_output ((char *) pool_start (running_shell[i].shell_pool), catstrs (s->name, _ (" Output "), 0), goto_file_callback, name); CAddWatch (running_shell[i].shell_pipe, shell_pool_update, WATCH_READING, (void *) i); return 1;}char *read_pipe (int fd, int *len);/* Returns shell_output on success, 0 on error. Result must be free'd. Unlike the above routine, this blocks waiting for the shell to exit. */static char *execute_foreground_shell (struct shell_cmd *s, char *script){ pid_t p = 0; char *argv[] = {0, 0}; int shell_foreground_pipe = -1; char *t; argv[0] = hme (SCRIPT_FILE); savefile (argv[0], script, strlen (script), 0700); if (s->options & SHELL_OPTION_INSERT_STDOUT) { if ((p = triple_pipe_open (0, &shell_foreground_pipe, 0, (s->options & SHELL_OPTION_INSERT_STDERR) ? 1 : 0, hme (SCRIPT_FILE), argv)) < 0) return 0; t = read_pipe (shell_foreground_pipe, 0); } else { if ((p = triple_pipe_open (0, 0, &shell_foreground_pipe, 0, hme (SCRIPT_FILE), argv)) < 0) return 0; t = read_pipe (shell_foreground_pipe, 0); if (!(s->options & SHELL_OPTION_INSERT_STDERR)) { if (t) free (t); t = (char *) strdup (""); } } if (shell_foreground_pipe >= 0) close (shell_foreground_pipe); kill_process (p); return t;}int edit_save_block (WEdit * edit, const char *filename, long start, long finish);/* This is called from the envokation dialog below */static int run_shell (WEdit * e, struct shell_cmd *s, char *cmdline_options, char *name){ struct stat st; long start_mark, end_mark; char *script; char *output = 0; int i; i = find_shell (0, name, 0); if (!(s->options & (SHELL_OPTION_DISPLAY_STDOUT_CONTINUOUS | SHELL_OPTION_DISPLAY_STDERR_CONTINUOUS))) /* --> these kill any running script automatically */ if (running_shell[i].shell_pid) { shell_error_dialog (_ (" Shell script "), _ (" A script is already running ")); return -1; } if (s->options & SHELL_OPTION_SAVE_BLOCK) { eval_marks (e, &start_mark, &end_mark); edit_save_block (e, hme (BLOCK_FILE), start_mark, end_mark); } if (s->options & SHELL_OPTION_SAVE_EDITOR_FILE) if (!edit_save_file (e, catstrs (e->dir, e->filename, 0))) if (!edit_save_as_cmd (e)) return -1; script = substitute_strings (s->script, cmdline_options, catstrs (e->dir, e->filename, 0), "", "", ""); if ((s->options & (SHELL_OPTION_DISPLAY_STDOUT_CONTINUOUS | SHELL_OPTION_DISPLAY_STDERR_CONTINUOUS | SHELL_OPTION_RUN_IN_BACKGROUND))) { if (!execute_background_shell (s, script, name)) { shell_error_dialog (_ (" Shell script "), get_sys_error (_ (" Error trying to pipe script. "))); return -1; } if (script) free (script); return 0; } else { CHourGlass (main_window); output = execute_foreground_shell (s, script); CUnHourGlass (main_window); if (!output) { shell_error_dialog (_ (" Shell script "), get_sys_error (_ (" Error trying to pipe script. "))); if (script) free (script); return -1; } } if (script) free (script); script = 0; if (s->options & SHELL_OPTION_CHECK_ERROR_FILE) { if (stat (hme (ERROR_FILE), &st) == 0) { if (st.st_size) { char *error; if (s->options & SHELL_OPTION_DISPLAY_ERROR_FILE) { error = loadfile (hme (ERROR_FILE), 0); if (error) { CTextboxMessageDialog (main_window, 20, 20, 80, 20, catstrs (s->name, _ (" Error "), 0), error, 0); free (error); } } return -1; } } } if (s->options & SHELL_OPTION_DELETE_BLOCK) if (edit_block_delete_cmd (e)) return 1; if (output) if (*output) for (i = strlen (output) - 1; i >= 0; i--) edit_insert_ahead (e, output[i]); if (output) free (output); if (s->options & SHELL_OPTION_INSERT_TEMP_FILE) if (!edit_insert_file (e, hme (TEMP_FILE))) shell_error_dialog (_ (" Shell script "), get_sys_error (_ (" Error trying to insert temp file. "))); if (s->options & SHELL_OPTION_INSERT_BLOCK_FILE) if (!edit_insert_file (e, hme (BLOCK_FILE))) shell_error_dialog (_ (" Shell script "), get_sys_error (_ (" Error trying to insert block file. "))); if (s->options & SHELL_OPTION_INSERT_CLIP_FILE) if (!edit_insert_file (e, hme (CLIP_FILE))) shell_error_dialog (_ (" Shell script "), get_sys_error (_ (" Error trying to insert clip file. "))); if (s->options & SHELL_OPTION_DISPLAY_ERROR_FILE) if (stat (hme (ERROR_FILE), &st) == 0) if (st.st_size) { /* no error messages */ char *error; error = loadfile (hme (ERROR_FILE), 0); if (error) { CTextboxMessageDialog (main_window, 20, 20, 80, 25, s->name, error, 0); free (error); } } return 0;}int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion);/* Main entry point. Request args if option is set and calls run_shell. Returns 0 on success, -1 on error and 1 on cancel. */static int run_shell_dialog (WEdit * e, struct shell_cmd *s){ char *cmdline_options; int r; long start_mark, end_mark; if (!s) return -1; if (s->options & SHELL_OPTION_SAVE_BLOCK) if (eval_marks (e, &start_mark, &end_mark)) { shell_error_dialog (_ (" Shell Script "), _ (" Script requires some text to be highlighted. ")); return 1; } if (s->options & SHELL_OPTION_REQUEST_ARGUMENTS) { char *p, *q; p = (char *) strdup (s->name); /* create a name for the input dialog by stripping spaces */ for (q = p; *q; q++) if (*q == ' ') memmove (q, q + 1, strlen (q)); if (strlen (p) > 20) p[20] = 0; cmdline_options = CInputDialog (p, 0, 0, 0, 40 * FONT_MEAN_WIDTH, s->last_options ? s->last_options : "", s->name, s->prompt); free (p); if (!cmdline_options) return 1; if (s->last_options) free (s->last_options); s->last_options = cmdline_options; } else { cmdline_options = ""; } r = run_shell (e, s, cmdline_options, s->menu); CRefreshEditor (e); return r;}static struct shell_cmd *scripts[MAX_NUM_SCRIPTS] ={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};/* loads from options file */void load_scripts (){ char *s = 0, *p, *q; unsigned char *r; int i = 0, n; memset (&running_shell, 0, sizeof (running_shell)); s = get_options_section (editor_options_file, "[Shell Scripts]"); if (!s) { goto load_default_scripts; } else { if (!*s) goto load_default_scripts; } p = q = s; for (i = 0; i < MAX_NUM_SCRIPTS; i++) { if (!*q || *q == '\n') break; q = strchr (p, '\n'); if (!q) break; *q++ = 0; scripts[i] = CMalloc (sizeof (struct shell_cmd)); memset (scripts[i], 0, sizeof (struct shell_cmd)); strncpy (scripts[i]->name, p, 39); p = q; q = strchr (p, '\n'); *q++ = 0; strncpy (scripts[i]->menu, p, 39); p = q; q = strchr (p, '\n'); *q++ = 0; scripts[i]->menu_hot_key = *p; p = q; q = strchr (p, '\n'); *q++ = 0; scripts[i]->key = (KeySym) atoi (p); p = q; q = strchr (p, '\n'); *q++ = 0; scripts[i]->keyboard_state = atoi (p); p = q; q = strchr (p, '\n'); *q++ = 0; strncpy (scripts[i]->prompt, p, 159); p = q; q = strchr (p, '\n'); *q++ = 0; scripts[i]->options = atoi (p); p = q; q = strchr (p, '\n'); *q++ = 0; scripts[i]->last_options = (char *) strdup (p); p = q; q = strchr (p, '\n'); *q++ = 0; scripts[i]->script = (char *) strdup (p); for (r = (unsigned char *) scripts[i]->script; *r; r++) if (*r == 129) *r = '\n'; p = q; } load_default_scripts: n = sizeof (default_scripts) / sizeof (struct shell_cmd); if (i < n) { for (; i < n; i++) { scripts[i] = CMalloc (sizeof (struct shell_cmd)); memset (scripts[i], 0, sizeof (struct shell_cmd)); memcpy (scripts[i], &default_scripts[i], sizeof (struct shell_cmd)); scripts[i]->script = (char *) strdup (default_scripts[i].script); } } if (s) free (s);}/* saves to options file */static void save_scripts (void){ char *s, *p; int i = 0, n; p = s = CMalloc (65536); /* make longer if overwrites */ while (scripts[i]) { unsigned char *t, *r; t = (unsigned char *) strdup (scripts[i]->script); for (r = t; *r; r++) if (*r == '\n') *r = 129; /* replace newlines with 129 */ sprintf (p, "%s\n%s\n%c\n%d\n%d\n%s\n%d\n%s\n%s\n%n", scripts[i]->name ? scripts[i]->name : 0, scripts[i]->menu ? scripts[i]->menu : 0, scripts[i]->menu_hot_key ? scripts[i]->menu_hot_key : ' ', (int) scripts[i]->key, (int) scripts[i]->keyboard_state, scripts[i]->prompt ? scripts[i]->prompt : "", (int) scripts[i]->options, scripts[i]->last_options ? scripts[i]->last_options : "", t, &n); free (t); p += n; i++; } *p++ = '\n'; *p = 0; save_options_section (editor_options_file, "[Shell Scripts]", s); free (s);}#define N_ITEMS 4extern CWidget *edit[];extern int current_edit;/* straight from the menu */static void script_menu_callback (unsigned long ignored)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -