static char rcsid[] = "$Id: mline.c,v 1.4 1992/11/08 23:29:54 mike Exp $"; /* $Log: mline.c,v $ * Revision 1.4 1992/11/08 23:29:54 mike * - Added view mode. * * Revision 1.3 1992/10/02 22:31:40 mike * - Some changes for the Atari ST/TT version. * * Revision 1.2 1992/09/14 18:03:42 mike * - First set of changes for the Atari ST/TT version. * * Revision 1.1 1992/09/05 01:13:32 mike * Initial revision * */ /* * MLINE.C piddle with the modeline & msg line */ /* Copyright 1990, 1991, 1992 Craig Durland * Distributed under the terms of the GNU General Public License. * Distributed "as is", without warranties of any kind, but comments, * suggestions and bug reports are welcome. */ #ifdef __STDC__ #include #define VA_START va_start #else /* __STDC__ */ #include #define VA_START(a,b) va_start(a) #endif #include #include "me2.h" #include "config.h" #ifdef atarist #include "stio.h" #endif #include "mm.h" /* for the modeline stuff */ extern char *strcpy(), *bag_to_string(); void mlputi(), t_putcs(); /* ******************************************************************** */ /* ************* Mode Line ******************************************** */ /* ******************************************************************** */ /* * Redisplay the mode line for window wp. This is the only routine that has * any idea of how the modeline is formatted. * If modeline-hook exists, call that to format the modeline. Take the last * character of the result and repeat it to the end of the line. This is * done to make life easier for the hook and prevent some possible display * problems. * Called by update() any time there is a window that needs its modeline * updated (hopefully not very often). * Default format: ** ME -- buffer-name -- File: file-name --------------------------------- ** ME -- buffer-name ---------------------------------------------------- -- ME [jam] -- buffer-name -- File: file-name ------------------------ */ int ml_hook; /* modeline-hook */ void modeline(wp) Window *wp; { extern char *MMvtoa(); /* in mm.c */ extern int overstrike; /* in random.c */ extern MMDatum RV; /* in mm.c */ register Buffer *bp = wp->wbuffer; /* buffer displayed in window */ register char *ptr, c; int n; n = wp->w_toprow +wp->w_ntrows; /* Row wp's mode line is on */ vtmove(n,0); /* Seek to wp's mode line */ munged_mline(); /* Redraw next time */ /* don't need to clear the modeline because I'm going to fill it */ #if WFDEBUG /* show the windows update flags */ vtputc((wp->w_flag & WFMODE) ? 'M' : '-'); vtputc((wp->w_flag & WFHARD) ? 'H' : '-'); vtputc((wp->w_flag & WFEDIT) ? 'E' : '-'); vtputc((wp->w_flag & WFMOVE) ? 'V' : '-'); vtputc((wp->w_flag & WFFORCE) ? 'F' : '-'); #endif if (bhook(bp,ml_hook)) /* try to run modeline-hook */ { ptr = MMvtoa(&RV); vtputs(ptr); c = ptr[strlen(ptr)-1]; while (vtputc(c)) ; /* repeat last char */ return; } /* modeline-hook doesn't exist so use the default */ if (bp->b_flags & BFVIEW) vtputs("%%"); else vtputs(is_buffer_modified(bp) ? "**" : "--"); /* has buffer changed? */ vtputs(" ME2 "); if (overstrike) vtputs("[jam] "); /* Buffer name */ vtputs("-- "); vtputs(get_dString(bp->b_bname)); vtputc(' '); if (*get_dString(bp->b_fname)!='\0') /* File name */ { vtputs("-- File: "); vtputs(get_dString(bp->b_fname)); vtputc(' '); } while (vtputc('-')); } /* ******************************************************************** */ /* ********** Mini Buffer ********************************************* */ /* ******************************************************************** */ /************************************************************************* Message line stuff follows 1. The msg line is not part of the text display, it lives its own life 2. Always force the cursor 3. Use mlwrite() or mlputs() to write to the msg line else be very carefull! *************************************************************************/ extern int MMask_pgm, t_nrow; /* * Erase the message line. This is a special routine because the message * line is not considered to be part of the virtual screen. It always * works immediately; the terminal buffer is flushed via a call to the * flusher. */ void mlerase() { movecursor(t_nrow,0,TRUE); t_eeol(); t_flush(); mline_dirty = FALSE; } /* * Ask a yes or no question in the message line. Must be answered with * something starting with n, N, y or Y. A CR ain't good enough! * Notes: * If this is called from program, only looks one arg - don't loop though * the entire arg list looking for "y" or "n"! * Input: * prompt: What to ask the user. " [y/n]? " is appended. * Returns: TRUE, FALSE, or ABORT. */ mlyesno(prompt) char *prompt; { char buf[128], answer[10]; strcat(strcpy(buf,prompt)," [y/n]? "); while (TRUE) { if (mlreply(buf,answer,sizeof(answer),0) == ABORT) return ABORT; if (*answer == 'y' || *answer == 'Y') return TRUE; if (*answer == 'n' || *answer == 'N') return FALSE; if (MMask_pgm) return FALSE; } /* never gets here */ } /* * Write a message into the message line. Keep track of the physical cursor * position. A small class of printf like format items is handled. * Set the "message line" flag TRUE. */ /*VARARGS1*/ #ifdef __STDC__ void mlwrite(char *fmt, ...) #else void mlwrite(fmt,va_alist) char *fmt; va_dcl #endif { register char c; va_list ap; movecursor(t_nrow,0,TRUE); VA_START(ap, fmt); while ((c = *fmt++) != '\0') { if (c != '%') t_putchar(c); else switch (c = *fmt++) { case 'd': mlputi(va_arg(ap,int),10); break; case 'x': mlputi(va_arg(ap,int),16); break; case 's': t_putcs(va_arg(ap,char *)); break; default: t_putchar(c); } } va_end(ap); t_eeol(); t_flush(); mline_dirty = TRUE; } /* * Write out a string. Like mlwrite() but no format. Control characters * are expanded. * This assumes that the characters in the string all have width "1" - * if this is not the case things will get screwed up a little. */ void mlputs(str) char *str; { movecursor(t_nrow,0,TRUE); t_putcs(str); t_eeol(); t_flush(); mline_dirty = *str; /* TRUE if msg line not blank */ } /* * Write out an integer, in the specified radix. * Update the physical cursor position. */ void mlputi(i,r) { register int q; static char hexdigits[] = "0123456789ABCDEF"; if (i < 0) { i = -i; t_putchar('-'); } q = i/r; if (q != 0) mlputi(q, r); t_putchar(hexdigits[i%r]); } /* dump a string to the terminal */ void t_puts(string) register char *string; { while (*string) t_putchar(*string++); } /* dump a string to the terminal, expanding control chars */ void t_putcs(str) register unsigned char *str; { register unsigned char c; while ((c = *str++)) { if (iscntrl(c)) { t_putchar('^'); c ^= 0x40; } t_putchar(c); } } /* ******************************************************************** */ /* ******* MLREPLY: query the user on the message line **************** */ /* ******************************************************************** */ int cc_trigger = CC_TRIGGER; /* the key that triggers command completion */ #if !LED mlinit() { return TRUE; } /* initialize the message line stuff */ /* * Write a prompt into the message line, then read back a response. Keep * track of the physical position of the cursor. If we are in a keyboard * macro throw the prompt away, and return the remembered response. This * lets macros run at full speed. The reply is always terminated by a * carriage return. Handle erase, clear-line, quote and abort keys. * Command completion: If you want it, set selector to the bits of the * lists to complete. 0 => no completion. * Note: It is NOT OK for prompt==buf since ^L and command completion both * both reuse the prompt. I don't like it either. * RETURNS: TRUE, FALSE or ABORT. */ mlreply(prompt,buf,nbuf,selector) char *prompt, *buf; int nbuf; /* max size of buf */ unsigned int selector; { unsigned char tmp[20]; register KeyCode c; register int cpos = 0, i; if (MMask_pgm) { if (!MMnext_arg(buf)) return ctrlg(FALSE,0); /* Zippie sez Yow! */ return ((*buf == '\0') ? FALSE : TRUE); } /* keyboard macro? */ if (get_McString(buf)) return ((*buf == '\0') ? FALSE : TRUE); selector &= CC_MASK; /* turn off lists I can't complete */ mlputs(prompt); nbuf--; /* leave room for \0 */ while (TRUE) { buf[cpos] = '\0'; /* save some code */ c = t_getchar(); if (selector && (c == cc_trigger || c == '?')) { if (c == '?') hbomb(buf,selector); else { complete(buf,selector); cpos = strlen(buf); } mlwrite("%s%s",prompt,buf); continue; } switch (c) { case 0x0A: case 0x0D: /* Return or newline == end of line */ if (!add_McString(buf)) return ABORT; t_putchar('\r'); t_flush(); return ((*buf=='\0') ? FALSE : TRUE); case 0x07: return ctrlg(FALSE,0); /* Bell == Abort */ case 0x7F: case 0x08: /* Backspace & Rubout == erase */ if (cpos != 0) { t_puts("\b \b"); if (iscntrl(buf[--cpos])) t_puts("\b \b"); t_flush(); } break; case 0x15: mlputs(prompt); cpos = 0; break; /* C-u: clear-line */ case 0xC: /* ^L */ screen_is_garbage = TRUE; update(); mlwrite("%s%s",prompt,buf); break; case 0x11: /* C-q: quote next char */ c = t_getchar(); /* get next char and fall though */ default: if ((c & 0xFF00) == 0) /* not a ME key */ { if (cpos #include extern char *Ltext; /* in ed/led.c */ static int extended_callback(); t_clearline(n) { movecursor(t_nrow,0,TRUE); if (!n) t_eeol(); return n; } #define COMPLETE 0 #define HELP 1 #define REDRAW 2 #define YANK 3 /* initialize the message line stuff */ mlinit() /* do this after t_open() and alloc_display() */ { extern int Lflags; init_Led(); Lmacskeys(); Ldo_fcn(LF_BINDKEY, LF_CALLBACK, REDRAW, CTRL|'L', LF_CALLBACK, COMPLETE, cc_trigger, LF_CALLBACK, HELP, '?', LF_EXTEND, YANK, CTRL|'Y', LF_ABORT, CTRL|'G', LF_UNDEF, CTRL|'C', LF_UNDEF, '\\', LF_STOP,LF_STOP); Lregister_callback(0, extended_callback); return TRUE; } static int selmask, /* a way to pass selector to the callback */ tigger = CC_TRIGGER; /* So I can detect changes */ /* If the cursor is moved out of the msg line, need to make sure to tell * Led to move it back. */ static int callback(kc,fcn) KeyCode kc; int fcn; { int saveit; /* Guard selmask against recursion. */ char buf[200]; switch(fcn) { case HELP: saveit = selmask; hbomb(Ltext,selmask); selmask = saveit; return Ldo_fcn(LF_CTYNC,LF_STOP); case COMPLETE: strcpy(buf,Ltext); complete(buf,selmask); return Ldo_fcn(LF_CLEAR_LINE,LF_INSERT_STRING,buf,LF_CTYNC,LF_STOP); case REDRAW: screen_is_garbage = TRUE; update(); return Ldo_fcn(LF_REDRAW,LF_STOP); } return LF_NOOP; } static int extended_callback(kc,fcn, op) KeyCode kc; int fcn, *op; { char *ptr; switch(fcn) { default: return FALSE; /* nothing I know about */ case YANK: if (ptr = bag_to_string(cut_buffer)) *op = Ldo_fcn(LF_INSERT_STRING,ptr,LF_CTYNC,LF_STOP); } return TRUE; } /* * Write a prompt into the message line, then read back a response. Keep * track of the physical position of the cursor. If we are in a keyboard * macro throw the prompt away, and return the remembered response. This * lets macros run at full speed. The reply is always terminated by a * carriage return. * Command completion: If you want it, set selector to the bits of the * lists to complete. 0 => no completion. * Note: It is OK for prompt==buf. * RETURNS: TRUE, FALSE or ABORT. */ mlreply(prompt,buf,nbuf,selector) char *prompt, *buf; int nbuf; /* max size of buf */ unsigned int selector; { if (MMask_pgm) { if (!MMnext_arg(buf)) return ctrlg(FALSE,0); /* Zippie sez Yow! */ return ((*buf == '\0') ? FALSE : TRUE); } /* keyboard macro? */ if (get_McString(buf)) return ((*buf == '\0') ? FALSE : TRUE); mline_dirty = TRUE; /* assume message line is gonna have stuff in it */ selector &= CC_MASK; /* turn off lists I can't complete */ selmask = selector; /* if the command completion trigger has changed, rebind */ if (selector && cc_trigger != tigger) { Ldo_fcn(LF_BINDKEY, LF_UNDEF,tigger, /* unbind old key */ LF_CALLBACK,COMPLETE,cc_trigger, /* bind to new key */ LF_STOP,LF_STOP); tigger = cc_trigger; } switch (Led(prompt,"",selector ? callback : (pfi)NULL)) { case LF_DONE: /* Return or newline == end of line */ strncpy(buf,Ltext,nbuf); buf[nbuf-1] = '\0'; if (!add_McString(buf)) return ABORT; t_putchar('\r'); t_flush(); return ((*buf == '\0') ? FALSE : TRUE); case LF_ABORT: case LF_ERROR: return ctrlg(FALSE,0); } /* NOTREACHED */ mlwrite("???????????????"); t_getchar(); } #endif /* !LED */