/* * Prompt windows * Copyright * (C) 1992 Joseph H. Allen * * This file is part of JOE (Joe's Own Editor) */ #include "types.h" /* The current directory */ int bg_prompt; int nocurdir; char *get_cd(W *w) { BW *bw; w = w->main; bw = (BW *)w->object; return bw->b->current_dir; } void set_current_dir(BW *bw, char *s,int simp) { W *w = bw->parent->main; B *b; bw = (BW *)w->object; b = bw->b; if (s[0]=='!' || (s[0]=='>' && s[1]=='>')) return; obj_free(b->current_dir); if (s) { b->current_dir=dirprt(s); if (simp) { b->current_dir = simplify_prefix(b->current_dir); } } else b->current_dir = 0; obj_perm(b->current_dir); } static void disppw(W *w, int flg) { BW *bw = (BW *)w->object; char *bf; int i; PW *pw = (PW *) bw->object; if (!flg) { return; } /* Try a nice graphics separator */ bf = joe_malloc(w->w + 1); for (i = 0; i != w->w; ++i) bf[i] = '-'; bf[i] = 0; genfmt(w->t->t, w->x, w->y, 0, bf, bg_stalin, 0); joe_free(bf); /* Scroll buffer and position prompt */ if (pw->promptlen > w->w - 5) { pw->promptofst = pw->promptlen - w->w / 2; if (piscol(bw->cursor) < w->w - (pw->promptlen - pw->promptofst)) { bw->offset = 0; } else { bw->offset = piscol(bw->cursor) - (w->w - (pw->promptlen - pw->promptofst) - 1); } } else { if (piscol(bw->cursor) < w->w - pw->promptlen) { pw->promptofst = 0; bw->offset = 0; } else if (piscol(bw->cursor) >= w->w) { pw->promptofst = pw->promptlen; bw->offset = piscol(bw->cursor) - (w->w - 1); } else { pw->promptofst = pw->promptlen - TO_DIFF_OK((w->w - piscol(bw->cursor) - 1)); bw->offset = piscol(bw->cursor) - (w->w - (pw->promptlen - pw->promptofst) - 1); } } /* Set cursor position */ w->curx = TO_DIFF_OK(piscol(bw->cursor) - bw->offset + pw->promptlen - pw->promptofst); w->cury = bw->cursor->line - bw->top->line + 1; /* w->cury = w->h - 1; */ /* Generate prompt */ w->t->t->updtab[w->y + w->cury] = 1; if (w->cury != pw->oldcury) { int n; for (n = 0; n != w->h; ++n) w->t->t->updtab[w->y + n] = 1; pw->oldcury = w->cury; } /* w->t->t->updtab[w->y + w->h - 1] = 1; genfmt(w->t->t, w->x, w->y + w->h - 1, pw->promptofst, pw->prompt, BG_COLOR(bg_prompt), 0); */ /* Position and size buffer */ /* bwmove(bw, w->x + pw->promptlen - pw->promptofst, w->y); bwresz(bw, w->w - (pw->promptlen - pw->promptofst), w->h); */ bwmove(bw, w->x, w->y + 1); bwresz(bw, w->w, w->h - 1); /* Generate buffer */ bwgen(bw, 0); } /* History functions */ void setup_history(B **history) { if (!*history) { *history = bmk(NULL); } } /* Add line to history buffer */ void append_history(B *hist,char *s,ptrdiff_t len) { P *q = pdup(hist->eof, "append_history"); binsm(q, s, len); p_goto_eof(q); binsc(q, '\n'); prm(q); } /* Promote line to end of history buffer */ void promote_history(B *hist, off_t line) { P *q = pdup(hist->bof, "promote_history"); P *r; P *t; pline(q, line); r = pdup(q, "promote_history"); pnextl(r); t = pdup(hist->eof, "promote_history"); binsb(t, bcpy(q, r)); bdel(q, r); prm(q); prm(r); prm(t); } /* When user hits return in a prompt window */ static int rtnpw(W *w) { BW *bw = (BW *)w->object; PW *pw = (PW *)bw->object; char *s; W *win; int (*pfunc)(W *w, char *s, void *object); void *object; off_t byte; /* Extract entered text from buffer */ p_goto_eol(bw->cursor); byte = bw->cursor->byte; p_goto_bol(bw->cursor); s = brvs(NULL, bw->cursor, TO_DIFF_OK(byte - bw->cursor->byte)); if (pw->file_prompt) { s = canonical(s); } /* Save text into history buffer */ if (pw->hist) { if (bw->b->changed) { append_history(pw->hist, sv(s)); } else { promote_history(pw->hist, bw->cursor->line); } } /* Do ~ expansion and set new current directory */ if (pw->file_prompt&2) { set_current_dir(bw, s,1); } win = w->win; pfunc = pw->pfunc; object = pw->object; bwrm(bw); joe_free(pw->prompt); joe_free(pw); w->object = NULL; wabort(w); dostaupd = 1; /* Call callback function */ if (pfunc) { return pfunc(win, s, object); } else { return -1; } } int ucmplt(W *w, int k) { BW *bw; PW *pw; WIND_BW(bw, w); pw = (PW *) bw->object; if (pw->tab) { return pw->tab(bw, k); } else { return -1; } } static void inspw(W *w, B *b, off_t l, off_t n, int flg) { BW *bw = (BW *)w->object; if (b == bw->b) { bwins(bw, l, n, flg); } } static void delpw(W *w, B *b, off_t l, off_t n, int flg) { BW *bw = (BW *)w->object; if (b == bw->b) { bwdel(bw, l, n, flg); } } static int abortpw(W *w) { BW *bw = (BW *)w->object; PW *pw = (PW *)bw->object; void *object = pw->object; int (*abrt)(W *w, void *object) = pw->abrt; W *win = bw->parent->win; bwrm(bw); joe_free(pw->prompt); joe_free(pw); if (abrt) { return abrt(win, object); } else { return -1; } } WATOM watompw = { "prompt", disppw, bwfllwt, abortpw, rtnpw, utypew, NULL, NULL, inspw, delpw, TYPEPW }; /* Create a prompt window */ BW *wmkpw(W *w, const char *prompt, B **history, int (*func) (W *w, char *s, void *object), const char *huh, int (*abrt)(W *w, void *object), int (*tab)(BW *bw, int k), void *object, struct charmap *map, int file_prompt) { W *neww; PW *pw; BW *bw; neww = wcreate(w->t, &watompw, w, w, w->main, 2, huh); if (!neww) { return NULL; } neww->fixed = 0; wfit(neww->t); neww->object = (void *) (bw = bwmk(neww, bmk(NULL), 0, prompt)); bw->b->o.charmap = map; bw->object = (void *) (pw = (PW *) joe_malloc(SIZEOF(PW))); pw->abrt = abrt; pw->oldcury = -1; pw->tab = tab; pw->object = object; pw->prompt = zdup(prompt); pw->promptlen = fmtlen(prompt); pw->promptofst = 0; pw->pfunc = func; pw->file_prompt = file_prompt; if (pw->file_prompt) { bw->b->o.syntax = load_syntax("filename"); bw->b->o.highlight = 1; bw->o.syntax = bw->b->o.syntax; bw->o.highlight = bw->b->o.highlight; } if (history) { setup_history(history); pw->hist = *history; binsb(bw->cursor, bcpy(pw->hist->bof, pw->hist->eof)); bw->b->changed = 0; p_goto_eof(bw->cursor); /* p_goto_eof(bw->top); p_goto_bol(bw->top); */ } else { pw->hist = NULL; } /* Install current directory */ if ((file_prompt&4) && !nocurdir) { char *curd = get_cd(w); binsm (bw->cursor, sv(curd)); p_goto_eof(bw->cursor); bw->cursor->xcol = piscol(bw->cursor); } w->t->curwin = neww; return bw; } /* Tab completion functions */ char **regsub(char **z, ptrdiff_t len, char *s) { char **lst = NULL; int x; for (x = 0; x != len; ++x) if (rmatch(s, z[x], 0)) lst = vaadd(lst, vsncpy(NULL, 0, sz(z[x]))); return lst; } void cmplt_ins(BW *bw, char *line) { P *p = pdup(bw->cursor, "cmplt_ins"); p_goto_bol(p); p_goto_eol(bw->cursor); bdel(p, bw->cursor); binsm(bw->cursor, sv(line)); p_goto_eol(bw->cursor); prm(p); bw->cursor->xcol = piscol(bw->cursor); } int cmplt_abrt(W *w, ptrdiff_t x, void *object) { char *line = (char *)object; if (line) { /* cmplt_ins(bw, line); */ obj_free(line); } return -1; } int cmplt_rtn(MENU *m, ptrdiff_t x, void *object, int k) { char *line = (char *)object; cmplt_ins((BW *)m->parent->win->object, m->list[x]); obj_free(line); m->object = NULL; wabort(m->parent); return 0; } int simple_cmplt(BW *bw,char **list) { MENU *m; P *p, *q; char *line; char *line1; char **lst; p = pdup(bw->cursor, "simple_cmplt"); p_goto_bol(p); q = pdup(bw->cursor, "simple_cmplt"); p_goto_eol(q); line = brvs(NULL, p, (int) (q->byte - p->byte)); /* Assumes short lines :-) */ prm(p); prm(q); line1 = vsncpy(NULL, 0, sv(line)); line1 = vsadd(line1, '*'); lst = regsub(av(list), line1); if (!lst) { ttputc(7); return -1; } if (menu_above) { if (bw->parent->link.prev->watom==&watommenu) { wabort(bw->parent->link.prev); } } else { if (bw->parent->link.next->watom==&watommenu) { wabort(bw->parent->link.next); } } obj_perm(line); vaperm(lst); m = mkmenu((menu_above ? bw->parent->link.prev : bw->parent), bw->parent, lst, cmplt_rtn, cmplt_abrt, NULL, 0, line); if (!m) { return -1; } if (valen(lst) == 1) return cmplt_rtn(m, 0, line, 0); else if (smode || isreg(line)) { if (!menu_jump) bw->parent->t->curwin=bw->parent; return 0; } else { char *com = mcomplete(m); obj_free(m->object); m->object = com; obj_perm(com); cmplt_ins(bw, com); wabort(m->parent); smode = 2; ttputc(7); return 0; } } /* Simplified prompting... convert original event-driven style to * coroutine model */ struct prompt_result { Coroutine t; char *answer; }; int prompt_cont(W *w, char *s, void *object) { struct prompt_result *r = (struct prompt_result *)object; r->answer = s; /* move answer to original coroutine's obj_stack */ obj_perm(r->answer); co_resume(&r->t, 0); return 0; } int prompt_abrt(W *w, void *object) { struct prompt_result *r = (struct prompt_result *)object; r->answer = 0; co_resume(&r->t, -1); return -1; } char *ask(W *w, /* Prompt goes below this window */ const char *prompt, /* Prompt text */ B **history, /* History buffer to use */ char *huh, /* Name of help screen for this prompt */ int (*tab)(), /* Called when tab key is pressed */ struct charmap *map, /* Character map for prompt */ int file_prompt, /* Set for file-name tilde expansion */ int retrieve_last, /* Set for cursor to go on last line of history */ char *preload) /* Text to preload into prompt */ { struct prompt_result t; BW *bw = wmkpw(w, prompt, history, prompt_cont, huh, prompt_abrt, tab, &t, map, file_prompt); if (!bw) return 0; bw->parent->coro = &t.t; if (preload) { /* Load hint, put cursor after it */ binss(bw->cursor, preload); pset(bw->cursor, bw->b->eof); bw->cursor->xcol = piscol(bw->cursor); } else if (retrieve_last) { /* One step back through history */ uuparw(w, NO_MORE_DATA); u_goto_eol(w, NO_MORE_DATA); bw->cursor->xcol = piscol(bw->cursor); } /* We get woken up when user hits return */ if (!co_yield(&t.t, 0)) { /* Moving answer to original coroutine's stack */ obj_temp(t.answer); return t.answer; } else { return 0; } }