mg: replace-regexp
This diff adds a non-interactive version of mg's query-replace-regexp function called replace-regexp. Unfortunately query-replace-regexp can't be used in a startup file. Ok? Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.172 diff -u -p -u -p -r1.172 def.h --- def.h 20 Apr 2021 10:02:50 - 1.172 +++ def.h 20 Apr 2021 16:12:50 - @@ -673,6 +673,7 @@ int re_forwsearch(int, int); int re_backsearch(int, int); int re_searchagain(int, int); int re_queryrepl(int, int); +int re_repl(int, int); int replstr(int, int); int setcasefold(int, int); int delmatchlines(int, int); Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.61 diff -u -p -u -p -r1.61 funmap.c --- funmap.c20 Apr 2021 10:02:50 - 1.61 +++ funmap.c20 Apr 2021 16:12:50 - @@ -181,6 +181,7 @@ static struct funmap functnames[] = { {reposition, "recenter", 0}, {redraw, "redraw-display", 0}, #ifdef REGEX + {re_repl, "replace-regexp", 2}, {replstr, "replace-string", 2}, #endif /* REGEX */ {revertbuffer, "revert-buffer", 0}, Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.123 diff -u -p -u -p -r1.123 mg.1 --- mg.120 Apr 2021 10:02:50 - 1.123 +++ mg.120 Apr 2021 16:12:50 - @@ -778,6 +778,8 @@ Display current (global) working directo .It query-replace Query Replace. Search and replace strings selectively, prompting after each match. +.It replace-regexp +Replace regular expression globally without individual prompting. .It replace-string Replace string globally without individual prompting. .It query-replace-regexp Index: re_search.c === RCS file: /cvs/src/usr.bin/mg/re_search.c,v retrieving revision 1.35 diff -u -p -u -p -r1.35 re_search.c --- re_search.c 22 Jul 2020 13:29:05 - 1.35 +++ re_search.c 20 Apr 2021 16:12:50 - @@ -211,6 +211,34 @@ stopsearch: return (TRUE); } +int +re_repl(int f, int n) +{ +int rcnt = 0; /* replacements made so far */ +int plen, s;/* length of found string */ +charnews[NPAT]; /* replacement string */ + +if ((s = re_readpattern("RE Replace")) != TRUE) +return (s); +if (eread("Replace %s with: ", news, NPAT, +EFNUL | EFNEW | EFCR, re_pat) == NULL) +return (ABORT); + + while (re_forwsrch() == TRUE) { + plen = regex_match[0].rm_eo - regex_match[0].rm_so; + if (re_doreplace((RSIZE)plen, news) == FALSE) + return (FALSE); + rcnt++; + } + + curwp->w_rflag |= WFFULL; + update(CMODE); + if (!inmacro) + ewprintf("(%d replacement(s) done)", rcnt); + + return(TRUE); +} + /* * Routine re_doreplace calls lreplace to make replacements needed by * re_query replace. Its reason for existence is to deal with \1, \2. etc.
mg list-buffers
This is the current format of the output of the mg 'list-buffer' command: MR Buffer Size File -- -- *Buffer List* 0 .** file1.c 6810 /tmp/file1.c file2.c 7105 /tmp/file2.c * *scratch* 0 The 'M' column indicates if the buffer is modified by having an asterisk next to the buffer name. The 'R' column indicates if a buffer is read-only by not having an asterisk in the 'R' column. Therefor the files above with an asterisk in the column next to them are writable. Isn't that unintuitive? Also, perhaps less confusing than the 'R' column, is the first column (note it doesn't have a header character), it has a '.' next to 'file1.c'. The '.' indicates that this is the active buffer in mg. Could a different character indicate the active buffer? The diff below makes the state of buffers above look like this: MR Buffer Size File -- -- * *Buffer List* 0 * file1.c 6810 /tmp/file1.c * file2.c 7105 /tmp/file2.c *scratch* 0 Read-only buffers have an asterisk in the 'R' column and I'm using a '>' character to indicate the active buffer. Is that better? Also, since I had to check the code to see what 'R' meant (I guessed 'M'), and I didn't even notice the '.' character (I thought it was a dodgy pixel), I have added a short explaination to the man page about the 3 columns. Objectsions, oks? Index: buffer.c === RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.111 diff -u -p -r1.111 buffer.c --- buffer.c23 Mar 2021 18:40:29 - 1.111 +++ buffer.c25 Mar 2021 15:08:36 - @@ -368,9 +368,9 @@ makelist(void) } if (addlinef(blp, "%c%c%c %-*.*s%c%-6d %-*s", - (bp == curbp) ? '.' : ' ', /* current buffer ? */ + (bp == curbp) ? '>' : ' ', /* current buffer ? */ ((bp->b_flag & BFCHG) != 0) ? '*' : ' ', /* changed ? */ - ((bp->b_flag & BFREADONLY) != 0) ? ' ' : '*', + ((bp->b_flag & BFREADONLY) != 0) ? '*' : ' ', w - 5, /* four chars already written */ w - 5, /* four chars already written */ bp->b_bname, /* buffer name */ Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.121 diff -u -p -r1.121 mg.1 --- mg.120 Mar 2021 09:00:49 - 1.121 +++ mg.125 Mar 2021 15:08:36 - @@ -692,6 +692,11 @@ directory. Toggle whether the line number is displayed in the modeline. .It list-buffers Display the list of available buffers. +The first column in the output indicates which buffer is active with a '>' +character. +The second column indicates which buffers are modified. +The third column indicates which buffers are read-only. +The remaining columns are self-explanatory. .It load Prompt the user for a filename, and then execute commands from that file.
mg: interactive evaluation
This diff gives mg the ability to have an interactive session with interpreter.c via the 'eval-current-buffer' command. With this diff the interactive mode is switched off by default of course. So if you are in the habit of evaluting startup files you won't see any difference. With this diff applied, you would need to give the 'M-x eval-interactive' command to toggle this functionality on. Even then you will only see a difference with 'eval-current-buffer' if there are commands with parenthesis* at the start of a line in the startup buffer you are evaluating. For example, having the following line in a buffer and executing 'eval-current-buffer' the behaviour is the same as previously: column-number-mode The command will toggle whether the column number shows in the modeline. If you instead have the following in the buffer: (column-number-mode) And issue the 'eval-current-buffer' command, with this diff applied (and whilst previously having toggled 'M-x eval-interactive' to on). You will achieve the same effect as the 1st command of toggling the column number in the modeline to on, but a buffer called *display-output* will have opened since you have entered the interpreter.c code by having '(' as the first none white character of the line. The contents of the *display-output* buffer will be empty because 'column-number-mode' creates no output. However with commands like: (insert "abc") The text "abc" will show in the *display-output* buffer. My initial goal is to have an interpreter that allows mg to combine different mg commands together and have some form of user defined functions, but I am a long way from that. The interpreter functionaility is still in the PoC stage and I wouldn't use it without expecting to see bugs (lots of them), and I expect it will go through more rewrites as I learn and understand more things about what is required. The functionality in the diff bellow allows me to test quicker though. As an outline, currently the interpreter can do things like: (define avar(list "a" "b" "c")) (insert avar) (newline 4) (insert avar) The string "abc" will appear twice in *display-output*, with 4 newline characters between them. Its pretty basic at the moment, I must admit I'm not intending this to be a scheme interpreter, but am using scheme syntax and a similar behaviour to be the glue of different mg commands which hopefully together can create mg user defined functions. This interpreter kind of functionality will also help me with intergrating mg's regress tests with OpenBSD's regress framework. For example, I am hoping to have something like: (define curdir(shell-command "echo $CURDIR")) To be able to import an environment variable, then use 'curdir' where required in mg's regress tests. If you would like to test, that would be much appreciated, there are also notes at the top of interpreter.c. I have not included anything in the mg man page about the interactive mode since I don't think the code is ready for that. Comments/oks/criticisms? Mark *parenthesis have been ignored in mg evaluation routines since mg being imported into the OpenBSD tree 21 years ago - and probably way before that, so I reckoned that no-one would have parenthesis in their startup files, or if they did, my interpreter code wouldn't change the behaviour of those lines anyway. Index: buffer.c === RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.111 diff -u -p -r1.111 buffer.c --- buffer.c23 Mar 2021 18:40:29 - 1.111 +++ buffer.c23 Mar 2021 22:58:45 - @@ -128,8 +128,6 @@ usebuffer(int f, int n) int poptobuffer(int f, int n) { - struct buffer *bp; - struct mgwin *wp; charbufn[NBUFN], *bufp; /* Get buffer to use from user */ @@ -142,6 +140,16 @@ poptobuffer(int f, int n) bufn, NBUFN, EFNUL | EFNEW | EFBUF, curbp->b_altb->b_bname); if (bufp == NULL) return (ABORT); + + return (do_poptobuffer(f, n, bufp)); +} + +int +do_poptobuffer(int f, int n, char *bufp) +{ + struct buffer *bp; + struct mgwin *wp; + if (bufp[0] == '\0' && curbp->b_altb != NULL) bp = curbp->b_altb; else if ((bp = bfind(bufp, TRUE)) == NULL) Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.170 diff -u -p -r1.170 def.h --- def.h 21 Mar 2021 12:56:16 - 1.170 +++ def.h 23 Mar 2021 22:58:45 - @@ -381,6 +381,7 @@ int writeout(FILE **, struct buffer *, voidupmodes(struct buffer *); size_t xbasename(char *, const char *, size_t); int do_filevisitalt(char *); +int do_poptofile(int, int, char *); /* line.c X */ struct line*lalloc(int); @@ -444,6 +445,7 @@ int revertbuffer(int, int); int dorevert(void); int
mg: buffer pointer change after eread()
When reading in from the modeline in buffer.c, mg uses a pointer called bufp pointing to a buffer called bufn. It would seem to make sense to use bufp in any further processing. These functions don't: switch-to-buffer-other-window (poptobuffer()) kill-buffer (killbuffer_cmd()) insert-buffer (bufferinsert()) This diff changes the above three instances to use bufp instead of bufn once eread() has been used. No functional change intended. ok? Index: buffer.c === RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.110 diff -u -p -r1.110 buffer.c --- buffer.c18 Mar 2021 18:09:21 - 1.110 +++ buffer.c23 Mar 2021 10:00:31 - @@ -144,7 +144,7 @@ poptobuffer(int f, int n) return (ABORT); if (bufp[0] == '\0' && curbp->b_altb != NULL) bp = curbp->b_altb; - else if ((bp = bfind(bufn, TRUE)) == NULL) + else if ((bp = bfind(bufp, TRUE)) == NULL) return (FALSE); if (bp == curbp) return (splitwind(f, n)); @@ -178,7 +178,7 @@ killbuffer_cmd(int f, int n) return (ABORT); else if (bufp[0] == '\0') bp = curbp; - else if ((bp = bfind(bufn, FALSE)) == NULL) + else if ((bp = bfind(bufp, FALSE)) == NULL) return (FALSE); ret = killbuffer(bp); eerase(); @@ -782,7 +782,7 @@ bufferinsert(int f, int n) return (ABORT); if (bufp[0] == '\0' && curbp->b_altb != NULL) bp = curbp->b_altb; - else if ((bp = bfind(bufn, FALSE)) == NULL) + else if ((bp = bfind(bufp, FALSE)) == NULL) return (FALSE); if (bp == curbp)
Re: mg(1): dired-jump
Should this be "if (fname != NULL)"? Some other callers of adjustname() check for a NULL pointer. strlen(NULL) would crash by SIGSEGV; strlen("") would return 0, because "" is a non-NULL pointer to an ASCII NUL '\0'. I agree. Amended diff below. Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.168 diff -u -p -r1.168 def.h --- def.h 1 Mar 2021 10:51:14 - 1.168 +++ def.h 19 Mar 2021 06:02:05 - @@ -363,6 +363,7 @@ int ask_makedir(void); /* dired.c */ struct buffer *dired_(char *); +int dired_jump(int, int); int do_dired(char *); /* file.c X */ Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.98 diff -u -p -r1.98 dired.c --- dired.c 5 Mar 2021 16:16:53 - 1.98 +++ dired.c 19 Mar 2021 06:02:05 - @@ -53,6 +53,7 @@ static int d_refreshbuffer(int, int); static int d_filevisitalt(int, int); static int d_gotofile(int, int); static void reaper(int); +static int gotofile(char*); static struct buffer *refreshbuffer(struct buffer *); static int createlist(struct buffer *); static void redelete(struct buffer *); @@ -1091,13 +1092,38 @@ createlist(struct buffer *bp) } int +dired_jump(int f, int n) +{ + char dname[NFILEN], *fname; + struct buffer *bp; + int ret; + + if (getbufcwd(dname, sizeof(dname)) != TRUE) + return (FALSE); + + fname = curbp->b_fname; + + if ((bp = dired_(dname)) == NULL) + return (FALSE); + curbp = bp; + + ret = showbuffer(bp, curwp, WFFULL | WFMODE); + if (ret != TRUE) + return ret; + + fname = adjustname(fname, TRUE); + if (fname != NULL) + gotofile(fname); + + return (TRUE); +} + +int d_gotofile(int f, int n) { - struct line *lp, *nlp; size_t lenfpath; - char fpath[NFILEN], fname[NFILEN]; - char*p, *fpth, *fnp = NULL; - int tmp; + char fpath[NFILEN]; + char*fpth, *fnp = NULL; if (getbufcwd(fpath, sizeof(fpath)) != TRUE) fpath[0] = '\0'; @@ -1114,8 +1140,18 @@ d_gotofile(int f, int n) ewprintf("No file to find"); /* Current directory given so */ return (TRUE); /* return at present location. */ } + return gotofile(fpth); +} + +int +gotofile(char *fpth) +{ + struct line *lp, *nlp; + char fname[NFILEN]; + char*p; + int tmp; + (void)xbasename(fname, fpth, NFILEN); - curbp = curwp->w_bufp; tmp = 0; for (lp = bfirstlp(curbp); lp != curbp->b_headp; lp = nlp) { tmp++; Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.59 diff -u -p -r1.59 funmap.c --- funmap.c11 Jul 2019 18:20:18 - 1.59 +++ funmap.c19 Mar 2021 06:02:05 - @@ -98,6 +98,7 @@ static struct funmap functnames[] = { {desckey, "describe-key-briefly", 1}, {diffbuffer, "diff-buffer-with-file", 0}, {digit_argument, "digit-argument", 1}, + {dired_jump, "dired-jump", 1}, {lowerregion, "downcase-region", 0}, {lowerword, "downcase-word", 0}, {showversion, "emacs-version", 0}, Index: keymap.c === RCS file: /cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.58 diff -u -p -r1.58 keymap.c --- keymap.c29 Dec 2015 19:44:32 - 1.58 +++ keymap.c19 Mar 2021 06:02:05 - @@ -129,7 +129,8 @@ static PF cXcB[] = { ctrlg /* ^G */ }; -static PF cXcL[] = { +static PF cXcJ[] = { + dired_jump, /* ^J */ lowerregion,/* ^L */ rescan, /* ^M */ rescan, /* ^N */ @@ -198,7 +199,7 @@ struct KEYMAPE (6) cXmap = { CCHR('B'), CCHR('G'), cXcB, NULL }, { - CCHR('L'), CCHR('X'), cXcL, NULL + CCHR('J'), CCHR('X'), cXcJ, NULL }, { '(', ')', cXlp, NULL Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.120 diff -u -p -r1.120 mg.1 --- mg.123 Feb 2021 18:45:33 - 1.120 +++ mg.119 Mar 2021 06:02:05 - @@ -198,6 +198,8 @@ list-buffers save-buffers-kill-emacs .It C-x C-f find-file +.It C-x C-j +dired-jump .It C-x C-g keyboard-quit .It C-x C-l @@ -523,6 +525,8 @@ Display the
mg(1): dired-jump
This diff was first seen on the tech list just under a year ago. It is from Philip K. and was tested by George Koehler. I have modified it slightly. From Philips original post: this patch implements "dired-jump" for mg. For those not familiar with what dired-jump does in GNU Emacs, here's it's docstring: Jump to Dired buffer corresponding to current buffer. If in a file, Dired the current directory and move to files line. I find this useful. ok? Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.168 diff -u -p -r1.168 def.h --- def.h 1 Mar 2021 10:51:14 - 1.168 +++ def.h 18 Mar 2021 20:15:34 - @@ -363,6 +363,7 @@ int ask_makedir(void); /* dired.c */ struct buffer *dired_(char *); +int dired_jump(int, int); int do_dired(char *); /* file.c X */ Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.98 diff -u -p -r1.98 dired.c --- dired.c 5 Mar 2021 16:16:53 - 1.98 +++ dired.c 18 Mar 2021 20:15:34 - @@ -53,6 +53,7 @@ static int d_refreshbuffer(int, int); static int d_filevisitalt(int, int); static int d_gotofile(int, int); static void reaper(int); +static int gotofile(char*); static struct buffer *refreshbuffer(struct buffer *); static int createlist(struct buffer *); static void redelete(struct buffer *); @@ -1091,13 +1092,38 @@ createlist(struct buffer *bp) } int +dired_jump(int f, int n) +{ + char dname[NFILEN], *fname; + struct buffer *bp; + int ret; + + if (getbufcwd(dname, sizeof(dname)) != TRUE) + return (FALSE); + + fname = curbp->b_fname; + + if ((bp = dired_(dname)) == NULL) + return (FALSE); + curbp = bp; + + ret = showbuffer(bp, curwp, WFFULL | WFMODE); + if (ret != TRUE) + return ret; + + fname = adjustname(fname, TRUE); + if (strlen(fname)) + gotofile(fname); + + return (TRUE); +} + +int d_gotofile(int f, int n) { - struct line *lp, *nlp; size_t lenfpath; - char fpath[NFILEN], fname[NFILEN]; - char*p, *fpth, *fnp = NULL; - int tmp; + char fpath[NFILEN]; + char*fpth, *fnp = NULL; if (getbufcwd(fpath, sizeof(fpath)) != TRUE) fpath[0] = '\0'; @@ -1114,8 +1140,18 @@ d_gotofile(int f, int n) ewprintf("No file to find"); /* Current directory given so */ return (TRUE); /* return at present location. */ } + return gotofile(fpth); +} + +int +gotofile(char *fpth) +{ + struct line *lp, *nlp; + char fname[NFILEN]; + char*p; + int tmp; + (void)xbasename(fname, fpth, NFILEN); - curbp = curwp->w_bufp; tmp = 0; for (lp = bfirstlp(curbp); lp != curbp->b_headp; lp = nlp) { tmp++; Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.59 diff -u -p -r1.59 funmap.c --- funmap.c11 Jul 2019 18:20:18 - 1.59 +++ funmap.c18 Mar 2021 20:15:34 - @@ -98,6 +98,7 @@ static struct funmap functnames[] = { {desckey, "describe-key-briefly", 1}, {diffbuffer, "diff-buffer-with-file", 0}, {digit_argument, "digit-argument", 1}, + {dired_jump, "dired-jump", 1}, {lowerregion, "downcase-region", 0}, {lowerword, "downcase-word", 0}, {showversion, "emacs-version", 0}, Index: keymap.c === RCS file: /cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.58 diff -u -p -r1.58 keymap.c --- keymap.c29 Dec 2015 19:44:32 - 1.58 +++ keymap.c18 Mar 2021 20:15:34 - @@ -129,7 +129,8 @@ static PF cXcB[] = { ctrlg /* ^G */ }; -static PF cXcL[] = { +static PF cXcJ[] = { + dired_jump, /* ^J */ lowerregion,/* ^L */ rescan, /* ^M */ rescan, /* ^N */ @@ -198,7 +199,7 @@ struct KEYMAPE (6) cXmap = { CCHR('B'), CCHR('G'), cXcB, NULL }, { - CCHR('L'), CCHR('X'), cXcL, NULL + CCHR('J'), CCHR('X'), cXcJ, NULL }, { '(', ')', cXlp, NULL Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.120 diff -u -p -r1.120 mg.1 --- mg.123 Feb 2021 18:45:33 - 1.120 +++ mg.1
mg(1): regress tests and pty
I am currently writing regress tests for mg which use an mg startup file's capabilities to process mg commands to test mg's internal functions. In order to facilitate mg fitting into the OpenBSD regress test framework and be able to run via a cron job I have amended mg to be able to run with a pty. The diff below adds a 'batch' mode to mg via the '-b' command line option which will initialise a pty, run the specified file of mg commands and then exit. There are other things to do to get mg fully integrated into the regress framework, but this diff is independant of them and offers a solution to no tty being available when being executed vi cron. Comments/oks/criticisms? Mark Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.168 diff -u -p -r1.168 def.h --- def.h 1 Mar 2021 10:51:14 - 1.168 +++ def.h 18 Mar 2021 15:58:39 - @@ -750,6 +750,7 @@ extern int doaudiblebell; extern int dovisiblebell; extern int dblspace; extern int allbro; +extern int batch; extern char cinfo[]; extern char*keystrings[]; extern char pat[NPAT]; Index: main.c === RCS file: /cvs/src/usr.bin/mg/main.c,v retrieving revision 1.88 diff -u -p -r1.88 main.c --- main.c 23 Feb 2021 08:10:51 - 1.88 +++ main.c 18 Mar 2021 15:58:40 - @@ -14,7 +14,9 @@ #include #include #include +#include #include +#include #include "def.h" #include "kbd.h" @@ -33,6 +35,7 @@ intdoaudiblebell; /* audible bell t int dovisiblebell; /* visible bell toggle */ int dblspace; /* sentence end #spaces */ int allbro;/* all buffs read-only */ +int batch; /* for regress tests*/ struct buffer *curbp; /* current buffer */ struct buffer *bheadp;/* BUFFER list head */ struct mgwin *curwp; /* current window */ @@ -40,6 +43,7 @@ struct mgwin *wheadp;/* MGWIN listhea charpat[NPAT]; /* pattern */ static void edinit(struct buffer *); +static void pty_init(void); static __dead void usage(void); extern char*__progname; @@ -48,8 +52,8 @@ extern void closetags(void); static __dead void usage() { - fprintf(stderr, "usage: %s [-nR] [-f mode] [-u file] [+number] " - "[file ...]\n", + fprintf(stderr, "usage: %s [-nR] [-b file] [-f mode] [-u file] " + " [+number] [file ...]\n", __progname); exit(1); } @@ -58,6 +62,7 @@ int main(int argc, char **argv) { char*cp, *conffile = NULL, *init_fcn_name = NULL; + char*batchfile = NULL; PF init_fcn = NULL; int o, i, nfiles; int nobackups = 0; @@ -67,8 +72,12 @@ main(int argc, char **argv) NULL) == -1) err(1, "pledge"); - while ((o = getopt(argc, argv, "nRf:u:")) != -1) + while ((o = getopt(argc, argv, "nRb:f:u:")) != -1) switch (o) { + case 'b': + batch = 1; + batchfile = optarg; + break; case 'R': allbro = 1; break; @@ -87,6 +96,20 @@ main(int argc, char **argv) default: usage(); } + + if (batch && (conffile != NULL)) { +fprintf(stderr, "%s: -b and -u are mutually exclusive.\n", +__progname); +exit(1); + } else if (batch) { + pty_init(); + conffile = batchfile; + } + if (conffile != NULL && access(conffile, R_OK) != 0) { +fprintf(stderr, "%s: Missing file: %s\n", __progname, conffile); +exit(1); + } + argc -= optind; argv += optind; @@ -136,6 +159,9 @@ main(int argc, char **argv) if ((cp = startupfile(NULL, conffile)) != NULL) (void)load(cp); + if (batch) + return (0); + /* * Now ensure any default buffer modes from the startup file are * given to any files opened when parsing the startup file. @@ -249,6 +275,26 @@ edinit(struct buffer *bp) wp->w_linep = wp->w_dotp = bp->b_headp; wp->w_ntrows = nrow - 2; /* 2 = mode, echo. */ wp->w_rflag = WFMODE | WFFULL; /* Full. */ +} + +/* + * Create pty for batch mode. + */ +static void +pty_init(void) +{ + struct winsize
Re: mg: Fix Coverity Scan warning: Insecure data handling
Thanks Todd. I'll pass your analysis on to Joachim. Date: Tue, 09 Mar 2021 14:14:33 -0700 From: Todd C. Miller To: Mark Lumsden Cc: tech@openbsd.org Subject: Re: mg: Fix Coverity Scan warning: Insecure data handling On Tue, 09 Mar 2021 20:14:19 +, Mark Lumsden wrote: Here is a diff from Joachim Wiberg's version of mg. "The strlcpy() function is guaranteed to never copy more than 'len - 1' bytes, so there is no need to check if we copied more. This is a bogus warning since the introduction of strlcpy()." That looks wrong to me. strlcpy() returns the number of bytes it would have copied if there was space. But if there was insufficient space then the return value can be larger. It is not safe to blindly use the return value without checking it first. - todd
mg: Fix Coverity Scan warning: Insecure data handling
Here is a diff from Joachim Wiberg's version of mg. "The strlcpy() function is guaranteed to never copy more than 'len - 1' bytes, so there is no need to check if we copied more. This is a bogus warning since the introduction of strlcpy()." Tested and seems reasonable. ok? Index: cinfo.c === RCS file: /cvs/src/usr.bin/mg/cinfo.c,v retrieving revision 1.18 diff -u -p -r1.18 cinfo.c --- cinfo.c 19 Mar 2015 21:22:15 - 1.18 +++ cinfo.c 9 Mar 2021 20:09:54 - @@ -106,7 +106,6 @@ char * getkeyname(char *cp, size_t len, int k) { const char *np; - size_t copied; if (k < 0) k = CHARMASK(k);/* sign extended char */ @@ -151,8 +150,6 @@ getkeyname(char *cp, size_t len, int k) *cp = '\0'; return (cp); } - copied = strlcpy(cp, np, len); - if (copied >= len) - copied = len - 1; - return (cp + copied); + + return (cp + strlcpy(cp, np, len)); }
Clear status line after killing or switching buffers
From Joachim Wiberg's version of mg. "This patch makes sure to clear the status/echo line after killing and switching buffers by name. Otherwise the kill/switch prompt lingers" ok? It also adds back a CVS tag on the first line of buffer.c that I inadvertantly removed a while back. Index: buffer.c === RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.109 diff -u -p -u -p -r1.109 buffer.c --- buffer.c1 Mar 2021 10:51:14 - 1.109 +++ buffer.c9 Mar 2021 17:19:25 - @@ -1,4 +1,4 @@ - +/* $OpenBSD$ */ /* This file is in the public domain. */ @@ -78,6 +78,7 @@ int usebufname(const char *bufp) { struct buffer *bp = NULL; + int rc; if (bufp == NULL) { if ((bp = bfind("*scratch*", TRUE)) == NULL) @@ -89,7 +90,10 @@ usebufname(const char *bufp) /* and put it in current window */ curbp = bp; - return (showbuffer(bp, curwp, WFFRAME | WFFULL)); + rc = showbuffer(bp, curwp, WFFRAME | WFFULL); + eerase(); + + return (rc); } /* @@ -165,6 +169,7 @@ killbuffer_cmd(int f, int n) { struct buffer *bp; charbufn[NBUFN], *bufp; + int rc; if (f & FFRAND) /* dired mode 'q' */ bp = curbp; @@ -175,7 +180,10 @@ killbuffer_cmd(int f, int n) bp = curbp; else if ((bp = bfind(bufn, FALSE)) == NULL) return (FALSE); - return (killbuffer(bp)); + rc = killbuffer(bp); + eerase(); + + return (rc); } int
mg: Dired opening directory error
If invoking 'M-x dired' and an error is encountered opening a directory, mg isn't very helpful. Though it will display a message on an EACCES problem. This diff doesn't go into the specifcs of which other error access(2) has encountered but does display an error msg: "Error opening: /non/existant/dir/" ok? Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.97 diff -u -p -u -p -r1.97 dired.c --- dired.c 1 Mar 2021 10:51:14 - 1.97 +++ dired.c 1 Mar 2021 13:26:49 - @@ -243,7 +243,7 @@ dired(int f, int n) dname[0] = '\0'; } - if ((bufp = eread("Dired: ", dname, NFILEN, + if ((bufp = eread("Dired (directory): ", dname, NFILEN, EFDEF | EFNEW | EFCR)) == NULL) return (ABORT); if (bufp[0] == '\0') @@ -928,6 +928,9 @@ dired_(char *dname) if (errno == EACCES) { dobeep(); ewprintf("Permission denied: %s", dname); + } else { + dobeep(); + ewprintf("Error opening: %s", dname); } return (NULL); }
Variablise \n and some regression tests
This diff puts the hardcoded '\n' character which is found throughout mg into a buffer specific variable. The diff should not produce any behavourial difference in mg, it is only to facilitate other work I am doing on mg. In order for me to validate that there is no behavioural difference I created some regression tests: https://mg-regress.s3-eu-west-1.amazonaws.com/regress.dir.007.tgz If you want to run the regressions tests, the instructions are in the file: regress/mg.regress.tests. The tests are performed by the mg eval-current-buffer function, they are not 'make' style tests. I will add more tests as time allows. Are there any objections to the diff? Or oks? Feedback on the tests, or more tests added would be appreciated. Mark Index: buffer.c === RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.107 diff -u -p -u -p -r1.107 buffer.c --- buffer.c24 Jun 2019 14:57:56 - 1.107 +++ buffer.c26 Feb 2021 14:33:43 - @@ -589,6 +589,8 @@ bnew(const char *bname) bheadp = bp; bp->b_dotline = bp->b_markline = 1; bp->b_lines = 1; + bp->b_nlseq = "\n";/* use unix default */ + bp->b_nlchr = bp->b_nlseq; if ((bp->b_bname = strdup(bname)) == NULL) { dobeep(); ewprintf("Can't get %d bytes", strlen(bname) + 1); @@ -1022,7 +1024,7 @@ diffbuffer(int f, int n) ttext += llength(lp); } if (lforw(lp) != lpend) /* no implied \n on last line */ - *ttext++ = '\n'; + *ttext++ = *curbp->b_nlchr; } bp = bfind("*Diff*", TRUE); Index: cscope.c === RCS file: /cvs/src/usr.bin/mg/cscope.c,v retrieving revision 1.18 diff -u -p -u -p -r1.18 cscope.c --- cscope.c3 Jul 2019 03:24:02 - 1.18 +++ cscope.c26 Feb 2021 14:33:43 - @@ -226,7 +226,7 @@ cscreatelist(int f, int n) addline(bp, title); addline(bp, ""); while ((len = getline(, , fpipe)) != -1) { - if (line[len - 1] == '\n') + if (line[len - 1] == *bp->b_nlchr) line[len - 1] = '\0'; addline(bp, line); } @@ -459,7 +459,7 @@ do_cscope(int i) addline(bp, ""); addline(bp, "---"); while ((len = getline(, , fpipe)) != -1) { - if (buf[len - 1] == '\n') + if (buf[len - 1] == *bp->b_nlchr) buf[len - 1] = '\0'; if (addentry(bp, buf) != TRUE) { free(buf); Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.167 diff -u -p -u -p -r1.167 def.h --- def.h 23 Feb 2021 08:10:51 - 1.167 +++ def.h 26 Feb 2021 14:33:43 - @@ -267,6 +267,8 @@ struct buffer { char b_flag;/* Flags */ char b_fname[NFILEN]; /* File name */ char b_cwd[NFILEN]; /* working directory */ + char*b_nlseq; /* Newline sequence of chars */ + char*b_nlchr; /* 1st newline character */ struct fileinfo b_fi; /* File attributes */ struct undoq b_undo;/* Undo actions list */ struct undo_rec *b_undoptr; Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.96 diff -u -p -u -p -r1.96 dired.c --- dired.c 26 Feb 2021 07:21:23 - 1.96 +++ dired.c 26 Feb 2021 14:33:43 - @@ -698,11 +698,12 @@ d_exec(int space, struct buffer *bp, con if ((fin = fdopen(fds[0], "r")) == NULL) goto out; while (fgets(buf, sizeof(buf), fin) != NULL) { - cp = strrchr(buf, '\n'); + cp = strrchr(buf, *bp->b_nlchr); if (cp == NULL && !feof(fin)) { /* too long a line */ int c; addlinef(bp, "%*s%s...", space, "", buf); - while ((c = getc(fin)) != EOF && c != '\n') + while ((c = getc(fin)) != EOF && + c != *bp->b_nlchr) ; continue; } else if (cp) Index: echo.c === RCS file: /cvs/src/usr.bin/mg/echo.c,v retrieving revision 1.66 diff -u -p -u -p -r1.66 echo.c --- echo.c 24 Oct 2016
mg: minibuffer anomaly
I was testing mg's goto-line function via the minibuffer (M-x goto-line) and I just kept my finger on the '0' key. After a brief time '0's started appearing in the main buffer, where the cursor had been. For a second I thought there had been an issue with memory allocation but after looking at the code I see what happens is when the memory allocated to the minibuffer fills up, a message "Line too long." should show in the minibuffer. It probably did, but since I was pressing the '0' key it disappeared instantly and I didn't realise that mg had tried to inform me of my error. mg then continued to accept my '0's as normal input. This diff soaks up the user input while the the maximum character length boundary is crossed in the minbuffer and allows the user to see the error message and respond accordingly. There may be other ways to handle this situation (like not pressing the '0' key so many times) but I think having mg do something is better than it *seemingly* not do anything. Any suggestions/preferences/better solutions? Mark Index: echo.c === RCS file: /cvs/src/usr.bin/mg/echo.c,v retrieving revision 1.66 diff -u -p -u -p -r1.66 echo.c --- echo.c 24 Oct 2016 17:18:42 - 1.66 +++ echo.c 25 Feb 2021 19:06:21 - @@ -336,8 +336,8 @@ veread(const char *fp, char *buf, size_t } if (!dynbuf && epos + 1 >= nbuf) { dobeep(); - ewprintf("Line too long"); - return (emptyval); + ewprintf("Line too long. Press Enter."); + goto null; } for (t = epos; t > cpos; t--) buf[t] = buf[t - 1]; @@ -492,8 +492,8 @@ veread(const char *fp, char *buf, size_t } if (!dynbuf && epos + 1 >= nbuf) { dobeep(); - ewprintf("Line too long"); - return (emptyval); + ewprintf("Line too long. Press Enter."); + goto null; } for (i = epos; i > cpos; i--) buf[i] = buf[i - 1]; @@ -507,6 +507,9 @@ veread(const char *fp, char *buf, size_t ttmove(rr, cc); ttflush(); } + +null: /* soak up any continuing key strokes */ +; } done: if (cwin == TRUE) {
mg: fix direction of mark-paragraph
The current direction of marking paragraphs using 'mark-paragraph' in mg is the opposite of emacs. Emacs goes backwards, mg goes forwards. This diff brings mg inline with emacs, and also simplifies the code, and fixes another bug with the current code. ok? Index: paragraph.c === RCS file: /cvs/src/usr.bin/mg/paragraph.c,v retrieving revision 1.46 diff -u -p -u -p -r1.46 paragraph.c --- paragraph.c 17 Nov 2018 09:52:34 - 1.46 +++ paragraph.c 23 Feb 2021 20:32:43 - @@ -302,23 +302,16 @@ killpara(int f, int n) int markpara(int f, int n) { - int i = 0; - if (n == 0) return (TRUE); clearmark(FFARG, 0); - if (findpara() == FALSE) - return (TRUE); - - (void)do_gotoeop(FFRAND, n, ); - /* set the mark here */ curwp->w_markp = curwp->w_dotp; curwp->w_marko = curwp->w_doto; - (void)gotobop(FFRAND, i); + (void)gotobop(FFRAND, n); return (TRUE); }
mg: specify a different startup file
This diff allows mg(1) to specify an alternative startup file on the fly when starting mg: $ mg -u ~/.mg2 I decided to use "u" since that is what emacs uses to load another user's init file: https://www.gnu.org/software/emacs/manual/html_node/emacs/Init-File.html Perhaps "f" would be better but that is being used to set mg modes Also, I decided not to load the default startup file if the alternative is not found since it seems more obvious that something is wrong that way. Any comments/ok? Mark Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.166 diff -u -p -u -p -r1.166 def.h --- def.h 9 Feb 2020 10:13:13 - 1.166 +++ def.h 21 Feb 2021 12:55:41 - @@ -471,7 +471,7 @@ int ffputbuf(FILE *, struct buffer *, int ffgetline(FILE *, char *, int, int *); int fbackupfile(const char *); char *adjustname(const char *, int); -char *startupfile(char *); +char *startupfile(char *, char *); int copy(char *, char *); struct list*make_file_list(char *); int fisdir(const char *); Index: fileio.c === RCS file: /cvs/src/usr.bin/mg/fileio.c,v retrieving revision 1.106 diff -u -p -u -p -r1.106 fileio.c --- fileio.c22 Jun 2019 10:21:57 - 1.106 +++ fileio.c21 Feb 2021 12:55:41 - @@ -330,7 +330,7 @@ adjustname(const char *fn, int slashslas * to the startup file name. */ char * -startupfile(char *suffix) +startupfile(char *suffix, char *conffile) { static char file[NFILEN]; char*home; @@ -339,7 +339,9 @@ startupfile(char *suffix) if ((home = getenv("HOME")) == NULL || *home == '\0') goto nohome; - if (suffix == NULL) { + if (conffile != NULL) { + (void)strncpy(file, conffile, NFILEN); + } else if (suffix == NULL) { ret = snprintf(file, sizeof(file), _PATH_MG_STARTUP, home); if (ret < 0 || ret >= sizeof(file)) return (NULL); Index: main.c === RCS file: /cvs/src/usr.bin/mg/main.c,v retrieving revision 1.87 diff -u -p -u -p -r1.87 main.c --- main.c 22 Jun 2019 15:38:15 - 1.87 +++ main.c 21 Feb 2021 12:55:41 - @@ -48,7 +48,8 @@ extern void closetags(void); static __dead void usage() { - fprintf(stderr, "usage: %s [-nR] [-f mode] [+number] [file ...]\n", + fprintf(stderr, "usage: %s [-nR] [-f mode] [-u file] [+number] " + "[file ...]\n", __progname); exit(1); } @@ -56,7 +57,7 @@ usage() int main(int argc, char **argv) { - char*cp, *init_fcn_name = NULL; + char*cp, *conffile = NULL, *init_fcn_name = NULL; PF init_fcn = NULL; int o, i, nfiles; int nobackups = 0; @@ -66,7 +67,7 @@ main(int argc, char **argv) NULL) == -1) err(1, "pledge"); - while ((o = getopt(argc, argv, "nRf:")) != -1) + while ((o = getopt(argc, argv, "nRf:u:")) != -1) switch (o) { case 'R': allbro = 1; @@ -80,6 +81,9 @@ main(int argc, char **argv) "initial function"); init_fcn_name = optarg; break; + case 'u': + conffile = optarg; + break; default: usage(); } @@ -129,7 +133,7 @@ main(int argc, char **argv) update(CMODE); /* user startup file. */ - if ((cp = startupfile(NULL)) != NULL) + if ((cp = startupfile(NULL, conffile)) != NULL) (void)load(cp); /* Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.118 diff -u -p -u -p -r1.118 mg.1 --- mg.18 Nov 2019 19:54:40 - 1.118 +++ mg.121 Feb 2021 12:55:42 - @@ -11,6 +11,7 @@ .Nm mg .Op Fl nR .Op Fl f Ar mode +.Op Fl u Ar file .Op + Ns Ar number .Op Ar .Sh DESCRIPTION @@ -38,6 +39,11 @@ line of the file, +-2 will be second las Run the mode command for all buffers created from arguments on the command line, including the scratch buffer and all files. +.It Fl u Ar file +Use +.Ar file +as the startup file, instead of the default +.Pa ~/.mg . .It Fl n Turn off backup file generation. .It Fl R Index: ttykbd.c === RCS file: /cvs/src/usr.bin/mg/ttykbd.c,v retrieving revision 1.19 diff -u -p -u -p -r1.19 ttykbd.c --- ttykbd.c17 Dec 2017 14:37:57 - 1.19 +++ ttykbd.c21 Feb 2021 12:55:42 - @@ -58,7
mg(1) list evaluation
This diff introduces lists to the startup file of mg. With this diff applied you could have something similar to: (define y(list b.txt c.txt)) (define z(list d.txt e.txt)) (find-file a.txt y f.txt z) in your .mg file, and when you opened mg, there would be 7 buffers opened (a.txt, b.txt, c.txt, d.txt, e.txt, and f.txt, including the *scratch* buffer) When I got about 3/4 of the way through this diff I realised I was probably not doing it the best way. I should have a list of 'key' words and multi-line parsing and lists within lists etc... I think I need to go back and take those ideas and apply them bit by bit to this diff. However, as a way forward does anyone object to this diff going in? My plan is to hopefully have some kind of user definable functions in mg, but functions (usually) need conditionals and variables, so I am trying to add in the basics beforehand. I'm using this for regress tests within mg, but arguably there could be other uses, depending on how much was developed. Like with the previous multi arg diff, if your .mg file has no '(' characters on the first line, you won't (or shouldn't) see any functional difference in mg. Any comments/objections? Mark Index: bell.c === RCS file: /cvs/src/usr.bin/mg/bell.c,v retrieving revision 1.4 diff -u -p -u -p -r1.4 bell.c --- bell.c 3 Jan 2016 19:37:08 - 1.4 +++ bell.c 15 Jul 2019 20:12:00 - @@ -26,6 +26,23 @@ bellinit(void) dovisiblebell = 0; } + +int +dobeep_msgs(const char *msg, const char *s) +{ + ewprintf("%s %s", msg, s); + dobeep(); + return (FALSE); +} + +int +dobeep_msg(const char *msg) +{ + ewprintf("%s", msg); + dobeep(); + return (FALSE); +} + void dobeep(void) { Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.162 diff -u -p -u -p -r1.162 def.h --- def.h 3 Jul 2019 18:11:07 - 1.162 +++ def.h 15 Jul 2019 20:12:00 - @@ -711,6 +711,8 @@ int compile(int, int); voidbellinit(void); int toggleaudiblebell(int, int); int togglevisiblebell(int, int); +int dobeep_msgs(const char *, const char *); +int dobeep_msg(const char *); voiddobeep(void); /* Index: extend.c === RCS file: /cvs/src/usr.bin/mg/extend.c,v retrieving revision 1.67 diff -u -p -u -p -r1.67 extend.c --- extend.c11 Jul 2019 18:20:18 - 1.67 +++ extend.c15 Jul 2019 20:12:00 - @@ -29,6 +29,17 @@ static intdobind(KEYMAP *, const char static char*skipwhite(char *); static char*parsetoken(char *); static int bindkey(KEYMAP **, const char *, KCHAR *, int); +static int clearvars(void); + +struct varentry { + SLIST_ENTRY(varentry) entry; + char*name; + char*vals; + int count; +}; +SLIST_HEAD(slisthead, varentry) varhead = SLIST_HEAD_INITIALIZER(varhead); + +#defineBUFSIZE 128 /* Size of line contents - could be larger? */ /* * Insert a string, mainly for use from macros (created by selfinsert). @@ -37,7 +48,7 @@ static int bindkey(KEYMAP **, const cha int insert(int f, int n) { - char buf[128], *bufp, *cp; + char buf[BUFSIZE], *bufp, *cp; int count, c; if (inmacro) { @@ -595,7 +606,7 @@ extend(int f, int n) int evalexpr(int f, int n) { - char exbuf[128], *bufp; + char exbuf[BUFSIZE], *bufp; if ((bufp = eread("Eval: ", exbuf, sizeof(exbuf), EFNEW | EFCR)) == NULL) @@ -616,18 +627,21 @@ evalbuffer(int f, int n) struct line *lp; struct buffer *bp = curbp; int s; - static char excbuf[128]; + static char excbuf[BUFSIZE]; for (lp = bfirstlp(bp); lp != bp->b_headp; lp = lforw(lp)) { - if (llength(lp) >= 128) + if (llength(lp) >= BUFSIZE) return (FALSE); (void)strncpy(excbuf, ltext(lp), llength(lp)); /* make sure it's terminated */ excbuf[llength(lp)] = '\0'; - if ((s = excline(excbuf)) != TRUE) + if ((s = excline(excbuf)) != TRUE) { + (void) clearvars(); return (s); + } } + (void) clearvars(); return (TRUE); } @@ -657,7 +671,7 @@ load(const char *fname) { int s = TRUE, line, ret; int nbytes = 0; - char excbuf[128], fncpy[NFILEN]; + char excbuf[BUFSIZE], fncpy[NFILEN]; FILE*ffp; if ((fname = adjustname(fname, TRUE)) == NULL) @@ -693,17 +707,39 @@ load(const char *fname) } /* - * Line has a '(' as the first
Re: mg(1) evaluate multi-argument commands
This is a modified diff of the previous evaluate multi-argument diff. The main difference is that all functions are given a number of parameters in the function map, this number represents how many arguments are required for the function to work. This extra column indicates to multiarg() how it should treat the list of arguments it receives, it needs to know how many arguments are 'normal' for the function being used, in order to separate the different invocations of the function to have the correct number of arguments. For example, this call to functionX: (functionX w x y z) Does functionX need 4 invocations, or 2, or 1? The new value is not used in any other situation other than evaluating the startup file or using an evaluate command, therefor it doesn't interfere with using mg as an interactive editor. I'd appreciate if this diff could be tested, to show if there are regressions in peoples .mg files. This diff does treat the '(' and ')' chars differently than previously, in-so-far as they are not ignored if they are at the end or start of a line now. However, even though these characters are not ignored, this diff should not change the behaviour of an extant .mg file, with '(' and ')' chars at the end and start of a line. This situation is accomodated for in this diff (with limited testing though). Does the above text explain what I am trying to do? In a general sense, this diff is to aid in the programability/extensibility of mg. If you have any thoughts or suggestions on how this could be acheived, please feel free to give me feedback/observations/criticisms etc.. Thanks. Mark Index: cmode.c === RCS file: /cvs/src/usr.bin/mg/cmode.c,v retrieving revision 1.16 diff -u -p -u -p -r1.16 cmode.c --- cmode.c 26 Sep 2015 21:51:58 - 1.16 +++ cmode.c 9 Jul 2019 16:54:49 - @@ -91,12 +91,12 @@ static struct KEYMAPE (3) cmodemap = { void cmode_init(void) { - funmap_add(cmode, "c-mode"); - funmap_add(cc_char, "c-handle-special-char"); - funmap_add(cc_brace, "c-handle-special-brace"); - funmap_add(cc_tab, "c-tab-or-indent"); - funmap_add(cc_indent, "c-indent"); - funmap_add(cc_lfindent, "c-indent-and-newline"); + funmap_add(cmode, "c-mode", 0); + funmap_add(cc_char, "c-handle-special-char", 0); + funmap_add(cc_brace, "c-handle-special-brace", 0); + funmap_add(cc_tab, "c-tab-or-indent", 0); + funmap_add(cc_indent, "c-indent", 0); + funmap_add(cc_lfindent, "c-indent-and-newline", 0); maps_add((KEYMAP *), "c"); } Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.92 diff -u -p -u -p -r1.92 dired.c --- dired.c 1 Jul 2019 19:36:17 - 1.92 +++ dired.c 9 Jul 2019 16:54:49 - @@ -204,24 +204,24 @@ static struct KEYMAPE (7) diredmap = { void dired_init(void) { - funmap_add(dired, "dired"); - funmap_add(d_create_directory, "dired-create-directory"); - funmap_add(d_copy, "dired-do-copy"); - funmap_add(d_expunge, "dired-do-flagged-delete"); - funmap_add(d_rename, "dired-do-rename"); - funmap_add(d_findfile, "dired-find-file"); - funmap_add(d_ffotherwindow, "dired-find-file-other-window"); - funmap_add(d_del, "dired-flag-file-deletion"); - funmap_add(d_gotofile, "dired-goto-file"); - funmap_add(d_forwline, "dired-next-line"); - funmap_add(d_otherwindow, "dired-other-window"); - funmap_add(d_backline, "dired-previous-line"); - funmap_add(d_refreshbuffer, "dired-revert"); - funmap_add(d_backpage, "dired-scroll-down"); - funmap_add(d_forwpage, "dired-scroll-up"); - funmap_add(d_undel, "dired-unmark"); - funmap_add(d_undelbak, "dired-unmark-backward"); - funmap_add(d_killbuffer_cmd, "quit-window"); + funmap_add(dired, "dired", 1); + funmap_add(d_create_directory, "dired-create-directory", 1); + funmap_add(d_copy, "dired-do-copy", 1); + funmap_add(d_expunge, "dired-do-flagged-delete", 0); + funmap_add(d_rename, "dired-do-rename", 1); + funmap_add(d_findfile, "dired-find-file", 1); + funmap_add(d_ffotherwindow, "dired-find-file-other-window", 1); + funmap_add(d_del, "dired-flag-file-deletion", 0); + funmap_add(d_gotofile, "dired-goto-file", 1); + funmap_add(d_forwline, "dired-next-line", 0); + funmap_add(d_otherwindow, "dired-other-window", 0); + funmap_add(d_backline, "dired-previous-line", 0); + funmap_add(d_refreshbuffer, "dired-revert", 0); + funmap_add(d_backpage, "dired-scroll-down", 0); + funmap_add(d_forwpage, "dired-scroll-up", 0); + funmap_add(d_undel, "dired-unmark", 0); + funmap_add(d_undelbak, "dired-unmark-backward", 0); + funmap_add(d_killbuffer_cmd, "quit-window", 0); maps_add((KEYMAP
Re: mg(1) evaluate multi-argument commands
I should add, I meant to put checks in for the calls to strlcpy and strlcat, but was pushed for time and forgot.. but of course they would be put in.
mg(1) evaluate multi-argument commands
I was finding it a bit tedious with long evaluation buffers so I wrote a function that would translate these three (or more) lines: find-file a.txt find-file b.txt find-file c.txt into this one line: (find-file a.txt b.txt c.txt) There are a few commands that can be used like this: insert, self-insert-char, kill-buffer, make-directory and some others. Interestingly 'insert-buffer' makes mg segv when used in this way, though it does behave the same without the below diff applied. I'll have to have a look and see why. I'm thinking I might write some kind of loop in the buffer evaulation code. However, does anyone object to this code? There is the side effect that the '(' and ')' characters are no longer seen as white space during buffer evaluation. Mark Index: extend.c === RCS file: /cvs/src/usr.bin/mg/extend.c,v retrieving revision 1.66 diff -u -p -u -p -r1.66 extend.c --- extend.c5 Jul 2019 14:50:59 - 1.66 +++ extend.c5 Jul 2019 14:58:23 - @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -693,6 +694,93 @@ load(const char *fname) } /* + * Line has a '(' as the first non-white char. + */ +int +multiarg(char *funstr) +{ + regex_t regex_buff; + PF funcp; + char excbuf[128]; + char*cmdp, *argp, *fendp, *endp, *p, *s = " "; + int singlecmd = 0, spc; + + endp = strrchr(funstr, ')'); + if (endp == NULL) { + ewprintf("No closing parenthesis found"); + return(FALSE); + } + p = endp + 1; + /* we now know that string starts with '(' and ends with ')' */ + *p = '\0'; + + if (regcomp(_buff, "^\([\t ]*)$", 0)) { + dobeep(); + ewprintf("Could not compile regex"); + return(FALSE); + } + if (!regexec(_buff, funstr, 0, NULL, 0)) { + dobeep(); + ewprintf("No command found"); + return(FALSE); + } + + /* currently there are no mg commands that don't have a letter */ + if (regcomp(_buff, "^\([\t ]*[A-Za-z]*[\t ]*)$", 0)) { + dobeep(); + ewprintf("Could not compile regex"); + return(FALSE); + } + if (!regexec(_buff, funstr, 0, NULL, 0)) + singlecmd = 1; + + p = funstr + 1; /* move past first '(' char.*/ + cmdp = skipwhite(p);/* find first char of command. */ + + if (singlecmd) { + cmdp[strlen(cmdp) - 1] = '\0'; /* remove ')'*/ + return(excline(cmdp)); + } + if (((fendp = strchr(cmdp, ' ')) == NULL) && + ((fendp = strchr(cmdp, '\t')) == NULL)) { + dobeep(); + ewprintf("Regular expression misuse"); + return (FALSE); + } + *fendp = '\0'; + + if ((funcp = name_function(cmdp)) == NULL) { + dobeep(); + ewprintf("Unknown command: %s", cmdp); + return (FALSE); + } + /* now find the first argument */ + p = fendp + 1; + argp = skipwhite(p); + spc = 1; /* initally fake a space so we find first argument */ + + for (p = argp; *p != '\0'; p++) { + if (*p == ' ' || *p == '\t' || *p == ')') { + if (spc == 0) { + *p = '\0'; /* terminate arg string */ + excbuf[0] = '\0'; + strlcpy(excbuf, cmdp, sizeof(excbuf)); + strlcat(excbuf, s, sizeof(excbuf)); + strlcat(excbuf, argp, sizeof(excbuf)); + excline(excbuf); + *p = ' '; /* so 'for' loop can continue */ + } + spc = 1; + } else { + if (spc == 1) + argp = p; + spc = 0; + } + } + return (TRUE); +} + +/* * excline - run a line from a load file or eval-expression. */ int @@ -724,6 +812,8 @@ excline(char *line) funcp = skipwhite(line); if (*funcp == '\0') return (TRUE); /* No error on blank lines */ + if (*funcp == '(') + return (multiarg(funcp)); line = parsetoken(funcp); if (*line != '\0') { *line++ = '\0'; @@ -928,7 +1018,7 @@ cleanup: static char * skipwhite(char *s) { - while (*s == ' ' || *s == '\t' || *s == ')' || *s == '(') + while (*s == ' ' || *s == '\t') s++; if ((*s == ';') || (*s == '#')) *s = '\0';
startup file - error message
If you have something like this in your .mg file: find-file /home/lum/test imaginary-command When you open mg you will see an error: Error loading file /home/lum/test at line 2 If you open files in your .mg file, but then have any kind of error with the evaluation of lines afterwards (even non file opening/closing errors), mg uses the last filename opened in the error message. Hence, the error should have said: Error loading file /home/lum/.mg at line 2 ..since 'imaginary-command' IS imaginary. Comments/oks? Mark Index: extend.c === RCS file: /cvs/src/usr.bin/mg/extend.c,v retrieving revision 1.65 diff -u -p -u -p -r1.65 extend.c --- extend.c22 Jun 2019 15:38:15 - 1.65 +++ extend.c3 Jul 2019 21:25:00 - @@ -657,7 +657,7 @@ load(const char *fname) { int s = TRUE, line, ret; int nbytes = 0; - char excbuf[128]; + char excbuf[128], fncpy[NFILEN]; FILE*ffp; if ((fname = adjustname(fname, TRUE)) == NULL) @@ -670,7 +670,8 @@ load(const char *fname) (void)ffclose(ffp, NULL); return (FALSE); } - + /* keep a copy of fname incase of evaluation errors in excline. */ + (void)strlcpy(fncpy, fname, sizeof(fncpy)); line = 0; while ((s = ffgetline(ffp, excbuf, sizeof(excbuf) - 1, )) == FIOSUC) { @@ -679,7 +680,7 @@ load(const char *fname) if (excline(excbuf) != TRUE) { s = FIOERR; dobeep(); - ewprintf("Error loading file %s at line %d", fname, line); + ewprintf("Error loading file %s at line %d", fncpy, line); break; } }
mg(1) self-insert-char
In order to test certain aspects of mg, I use the eval-current-buffer function. However, that doesn't let me insert a character like 'a' unless mg is getting that character from another file or previously existing text, somewhere on disk, or in RAM. This diff allows eval-current-buffer (or an mg startup file) to insert a character into a buffer via the self-insert-char function, which emulates the self-insert-command. For example: find-file test self-insert-char a self-insert-char b self-insert-char c newline save-buffer The above would create a file called test (if it didn't exist already) with the contents 'abc\n' when invoked via eval-current-buffer (or an mg startup file). The self-insert-command (which is the usual way of inserting a character into a buffer - but invoked via a 'normal' key press, not M-x self-insert-command) has other functionality when invoked via eval-current-buffer (or an mg startup file), see the man page. However, I may have missed some functionality of mg that allows a character to be inserted into a buffer via eval-current-buffer in this way. If so, please let me know. Though this new function does use the code I want to use/test (self-insert-command). Also, I have not included a man page addition since I am not too sure how useful the new function is to others. However should you run mg regress tests, it could be useful. Comments/criticisms/advice welcome. As are oks. Mark Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.161 diff -u -p -u -p -r1.161 def.h --- def.h 2 Jul 2019 16:25:39 - 1.161 +++ def.h 2 Jul 2019 16:56:09 - @@ -490,6 +490,7 @@ int rescan(int, int); int universal_argument(int, int); int digit_argument(int, int); int negative_argument(int, int); +int ask_selfinsert(int, int); int selfinsert(int, int); int quote(int, int); Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.57 diff -u -p -u -p -r1.57 funmap.c --- funmap.c2 Jul 2019 16:25:39 - 1.57 +++ funmap.c2 Jul 2019 16:56:09 - @@ -179,6 +179,7 @@ static struct funmap functnames[] = { {searchagain, "search-again",}, {backsearch, "search-backward",}, {forwsearch, "search-forward",}, + {ask_selfinsert, "self-insert-char",}, {selfinsert, "self-insert-command",}, {sentencespace, "sentence-end-double-space",}, #ifdef REGEX Index: kbd.c === RCS file: /cvs/src/usr.bin/mg/kbd.c,v retrieving revision 1.32 diff -u -p -u -p -r1.32 kbd.c --- kbd.c 26 Jun 2019 16:54:29 - 1.32 +++ kbd.c 2 Jul 2019 16:56:09 - @@ -323,6 +323,22 @@ negative_argument(int f, int n) return (mgwrap(funct, FFNEGARG, nn)); } +int +ask_selfinsert(int f, int n) +{ + char*c, cbuf[2]; + + if ((c = eread("Insert a character: ", cbuf, sizeof(cbuf), + EFNEW)) == NULL || (c[0] == '\0')) + return (ABORT); + + key.k_chars[0] = *c; + key.k_chars[1] = '\0'; + key.k_count = 1; + + return (selfinsert(FFRAND, 1)); +} + /* * Insert a character. While defining a macro, create a "LINE" containing * all inserted characters.
Re: mg(1) M-x blink-and-insert
I totally forgot about the instance where blink-and-insert can be called from the mg startup file. My previous diff broke that instance. So this diff reverts my change but adds a man page line to blink-and-insert (and comment). ok? Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.160 diff -u -p -u -p -r1.160 def.h --- def.h 26 Jun 2019 16:42:30 - 1.160 +++ def.h 1 Jul 2019 17:00:48 - @@ -642,7 +642,6 @@ void ttykeymapinit(void); voidttykeymaptidy(void); /* match.c X */ -int ask_showmatch(int, int); int showmatch(int, int); /* version.c X */ Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.56 diff -u -p -u -p -r1.56 funmap.c --- funmap.c26 Jun 2019 16:42:30 - 1.56 +++ funmap.c1 Jul 2019 17:00:48 - @@ -39,7 +39,7 @@ static struct funmap functnames[] = { {backword, "backward-word",}, {gotobob, "beginning-of-buffer",}, {gotobol, "beginning-of-line",}, - {ask_showmatch, "blink-and-insert",}, + {showmatch, "blink-and-insert",}, {bsmap, "bsmap-mode",}, {NULL, "c-x 4 prefix",}, {NULL, "c-x prefix",}, Index: match.c === RCS file: /cvs/src/usr.bin/mg/match.c,v retrieving revision 1.20 diff -u -p -u -p -r1.20 match.c --- match.c 26 Jun 2019 16:42:30 - 1.20 +++ match.c 1 Jul 2019 17:00:48 - @@ -35,30 +35,11 @@ static struct balance { { '\0', '\0' } }; - /* - * Self-insert character, then show matching character. - * Bound to "blink-and-insert". - */ -int -ask_showmatch(int f, int n) -{ - char*c, cbuf[2]; - - if ((c = eread("Insert a character: ", cbuf, sizeof(cbuf), - EFNEW)) == NULL || (c[0] == '\0')) - return (ABORT); - - key.k_chars[0] = *c; - key.k_chars[1] = '\0'; - key.k_count = 1; - - return (showmatch(FFRAND, 1)); -} - - -/* - * Hack to show matching paren. Bound to balance stucture chars ),],}. + * Hack to show matching paren. Self-insert character, then show matching + * character, if any. Bound to "blink-and-insert". Used in the mg startup + * file to amend the default cursor behaviour of a key press, e.g: + * global-set-key "%" blink-and-insert */ int showmatch(int f, int n) Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.115 diff -u -p -u -p -r1.115 mg.1 --- mg.117 Jun 2019 11:39:26 - 1.115 +++ mg.11 Jul 2019 17:00:48 - @@ -417,6 +417,7 @@ matching delimiter. For delimiters other than parenthesis, brackets, and braces, the character itself is used as its own match. +Can be used in the startup file with the global-set-key command. .It bsmap-mode Toggle bsmap mode, where DEL and C-h are swapped. .It c-mode
mg(1) dired-goto-file
This add dired-goto-file to mg. Comments/ok? Mark Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.90 diff -u -p -u -p -r1.90 dired.c --- dired.c 28 Jun 2019 13:35:02 - 1.90 +++ dired.c 29 Jun 2019 16:47:06 - @@ -51,6 +51,7 @@ static int d_backline(int, int); static int d_killbuffer_cmd(int, int); static int d_refreshbuffer(int, int); static int d_filevisitalt(int, int); +static int d_gotofile(int, int); static void reaper(int); static struct buffer *refreshbuffer(struct buffer *); static int createlist(struct buffer *); @@ -127,7 +128,10 @@ static PF direda[] = { d_del, /* d */ d_findfile, /* e */ d_findfile, /* f */ - d_refreshbuffer /* g */ + d_refreshbuffer,/* g */ + rescan, /* h */ + rescan, /* i */ + d_gotofile /* j */ }; static PF diredn[] = { @@ -186,7 +190,7 @@ static struct KEYMAPE (7) diredmap = { CCHR('Z'), '+', diredcz, (KEYMAP *) & metamap }, { - 'a', 'g', direda, NULL + 'a', 'j', direda, NULL }, { 'n', 'x', diredn, NULL @@ -208,6 +212,7 @@ dired_init(void) funmap_add(d_findfile, "dired-find-file"); funmap_add(d_ffotherwindow, "dired-find-file-other-window"); funmap_add(d_del, "dired-flag-file-deletion"); + funmap_add(d_gotofile, "dired-goto-file"); funmap_add(d_forwline, "dired-next-line"); funmap_add(d_otherwindow, "dired-other-window"); funmap_add(d_backline, "dired-previous-line"); @@ -1071,6 +1076,51 @@ createlist(struct buffer *bp) nlp = lforw(lp); } return (ret); +} + +int +d_gotofile(int f, int n) +{ + struct line *lp, *nlp; + struct buffer *curbp; + char fpath[NFILEN], fname[NFILEN]; + char*p, *fnp = NULL; + int tmp; + + if (getbufcwd(fpath, sizeof(fpath)) != TRUE) + fpath[0] = '\0'; + fnp = eread("Goto file: ", fpath, NFILEN, + EFNEW | EFCR | EFFILE | EFDEF); + if (fnp == NULL) + return (ABORT); + else if (fnp[0] == '\0') + return (FALSE); + + (void)xbasename(fname, fpath, NFILEN); + curbp = curwp->w_bufp; + tmp = 0; + for (lp = bfirstlp(curbp); lp != curbp->b_headp; lp = nlp) { + tmp++; + if ((p = findfname(lp, p)) == NULL) { + nlp = lforw(lp); + continue; + } + if (strcmp(fname, p) == 0) { + curwp->w_dotp = lp; + curwp->w_dotline = tmp; + (void)d_warpdot(curwp->w_dotp, >w_doto); + tmp--; + break; + } + nlp = lforw(lp); + } + if (tmp == curbp->b_lines - 1) { + ewprintf("File not found %s", fname); + return (FALSE); + } else { + ewprintf(""); + return (TRUE); + } } /* Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.115 diff -u -p -u -p -r1.115 mg.1 --- mg.117 Jun 2019 11:39:26 - 1.115 +++ mg.129 Jun 2019 16:47:06 - @@ -983,6 +983,8 @@ dired-do-copy dired-flag-file-deletion .It g dired-revert +.It j +dired-goto-file .It o dired-find-file-other-window .It p @@ -1025,6 +1027,8 @@ is executed. .It dired-find-file-other-window Open the file on the current line of the dired buffer in a different window. +.It dired-goto-file +Move the cursor to a file name in the dired buffer. .It dired-next-line Move the cursor to the next line. .It dired-other-window
mg(1) copy file in dired mode
In dired mode, if you try to copy a file without giving the new path a file name, similar to: cp /xdir/ydir/filname /xdir/ mg fails silently and doesn't copy the file into 'xdir' by using the existing filename as the copied filename. This diff uses the existing filename as the new filename if none is specified. Comments/ok? Mark Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.85 diff -u -p -u -p -r1.85 dired.c --- dired.c 25 Jun 2019 13:51:47 - 1.85 +++ dired.c 25 Jun 2019 15:22:19 - @@ -445,6 +445,7 @@ d_expunge(int f, int n) int d_copy(int f, int n) { + struct stat statbuf; char frname[NFILEN], toname[NFILEN], sname[NFILEN]; char*topath, *bufp; int ret; @@ -471,6 +472,18 @@ d_copy(int f, int n) return (FALSE); topath = adjustname(toname, TRUE); + if (stat(topath, ) == 0) { + if (S_ISDIR(statbuf.st_mode)) { + off = snprintf(toname, sizeof(toname), "%s/%s", + topath, sname); + if (off < 0 || off >= sizeof(toname) - 1) { + dobeep(); + ewprintf("Directory name too long"); + return (FALSE); + } + topath = adjustname(toname, TRUE); + } + } ret = (copy(frname, topath) >= 0) ? TRUE : FALSE; if (ret != TRUE) return (ret);
mg(1) M-x blink-and-insert
The man page for mg says this about blink-and-insert: blink-and-insert Self-insert a character, then search backwards and blink its matching delimiter. For delimiters other than parenthesis, brackets, and braces, the character itself is used as its own match. However, if you do 'M-x blink-and-insert', mg inserts an 'x' character at the cursor and then tries to find the previous 'x' character. By, 'x', I mean a literal 'x' character, not a user typed character. The 'x' would seem to come from the keystroke 'M-x'. Which is very handy if you want to insert an 'x' and find a match with the previous 'x' (if there is one). This diff attempts to make blink-and-insert do as the man page says it should do. If you do 'M-x blink-and-insert', you are asked for a character. mg will then insert it at the current cursor position and then search backwards for a corresponding match. The normal behaviour of typing a ),] or } hasn't changed. Comments/ok? Mark Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.159 diff -u -p -u -p -r1.159 def.h --- def.h 22 Jun 2019 15:38:15 - 1.159 +++ def.h 24 Jun 2019 19:20:11 - @@ -642,6 +642,7 @@ void ttykeymapinit(void); voidttykeymaptidy(void); /* match.c X */ +int ask_showmatch(int, int); int showmatch(int, int); /* version.c X */ Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.55 diff -u -p -u -p -r1.55 funmap.c --- funmap.c13 Dec 2018 14:59:16 - 1.55 +++ funmap.c24 Jun 2019 19:20:11 - @@ -39,7 +39,7 @@ static struct funmap functnames[] = { {backword, "backward-word",}, {gotobob, "beginning-of-buffer",}, {gotobol, "beginning-of-line",}, - {showmatch, "blink-and-insert",}, + {ask_showmatch, "blink-and-insert",}, {bsmap, "bsmap-mode",}, {NULL, "c-x 4 prefix",}, {NULL, "c-x prefix",}, Index: match.c === RCS file: /cvs/src/usr.bin/mg/match.c,v retrieving revision 1.19 diff -u -p -u -p -r1.19 match.c --- match.c 3 Jun 2015 23:40:01 - 1.19 +++ match.c 24 Jun 2019 19:20:11 - @@ -35,9 +35,30 @@ static struct balance { { '\0', '\0' } }; + /* - * Hack to show matching paren. Self-insert character, then show matching - * character, if any. Bound to "blink-and-insert". + * Self-insert character, then show matching character. + * Bound to "blink-and-insert". + */ +int +ask_showmatch(int f, int n) +{ + char*c, cbuf[2]; + + if ((c = eread("Insert a character: ", cbuf, sizeof(cbuf), + EFNEW)) == NULL || (c[0] == '\0')) + return (ABORT); + + key.k_chars[0] = *c; + key.k_chars[1] = '\0'; + key.k_count = 1; + + return (showmatch(FFRAND, 1)); +} + + +/* + * Hack to show matching paren. Bound to balance stucture chars ),],}. */ int showmatch(int f, int n)
mg(1): don't withold data indefinitely.
Currently if you have a file 'test' and cat it: $ cat test abc def ghk $ Then open 'test' in mg and remove the newline at the end of the buffer and try to save it, mg will offer the opportunity to add a newline at the end of the buffer: "No newline at end of file, add one? (y or n)" Before you answer this question, if you then cat the 'test' file again you will see: $ cat test $ mg is waiting for your answer before writing the contents of the buffer to disk (the file it has already opened for writing). This diff moves the check for the newline at the end of the buffer earlier so file data doesn't 'disappear' for an indefinite period (or arguably infinite period, if mg or the machine mg is running on crashes) before the user answers yes or no. Comments/ok? Mark Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.157 diff -u -p -u -p -r1.157 def.h --- def.h 13 Dec 2018 14:59:16 - 1.157 +++ def.h 20 Jun 2019 17:17:06 - @@ -466,7 +466,7 @@ int ffropen(FILE **, const char *, str voidffstat(FILE *, struct buffer *); int ffwopen(FILE **, const char *, struct buffer *); int ffclose(FILE *, struct buffer *); -int ffputbuf(FILE *, struct buffer *); +int ffputbuf(FILE *, struct buffer *, int); int ffgetline(FILE *, char *, int, int *); int fbackupfile(const char *); char *adjustname(const char *, int); Index: file.c === RCS file: /cvs/src/usr.bin/mg/file.c,v retrieving revision 1.100 diff -u -p -u -p -r1.100 file.c --- file.c 2 Jan 2016 10:39:19 - 1.100 +++ file.c 20 Jun 2019 17:17:06 - @@ -668,9 +668,10 @@ makebkfile(int f, int n) int writeout(FILE ** ffp, struct buffer *bp, char *fn) { - struct stat statbuf; - int s; - char dp[NFILEN]; + struct stat statbuf; + struct line *lpend; + int s, eobnl; + char dp[NFILEN]; if (stat(fn, ) == -1 && errno == ENOENT) { errno = 0; @@ -686,10 +687,16 @@ writeout(FILE ** ffp, struct buffer *bp, return (FIOERR); } } + lpend = bp->b_headp; + eobnl = 0; + if (llength(lback(lpend)) != 0) { + if (eyorn("No newline at end of file, add one") == TRUE) + eobnl = 1; + } /* open writes message */ if ((s = ffwopen(ffp, fn, bp)) != FIOSUC) return (FALSE); - s = ffputbuf(*ffp, bp); + s = ffputbuf(*ffp, bp, eobnl); if (s == FIOSUC) { /* no write error */ s = ffclose(*ffp, bp); Index: fileio.c === RCS file: /cvs/src/usr.bin/mg/fileio.c,v retrieving revision 1.105 diff -u -p -u -p -r1.105 fileio.c --- fileio.c13 Apr 2018 14:11:37 - 1.105 +++ fileio.c20 Jun 2019 17:17:06 - @@ -150,11 +150,12 @@ ffclose(FILE *ffp, struct buffer *bp) * buffer. Return the status. */ int -ffputbuf(FILE *ffp, struct buffer *bp) +ffputbuf(FILE *ffp, struct buffer *bp, int eobnl) { - struct line *lp, *lpend; + struct line *lp, *lpend; lpend = bp->b_headp; + for (lp = lforw(lpend); lp != lpend; lp = lforw(lp)) { if (fwrite(ltext(lp), 1, llength(lp), ffp) != llength(lp)) { dobeep(); @@ -164,14 +165,9 @@ ffputbuf(FILE *ffp, struct buffer *bp) if (lforw(lp) != lpend) /* no implied \n on last line */ putc('\n', ffp); } - /* -* XXX should be variable controlled (once we have variables) -*/ - if (llength(lback(lpend)) != 0) { - if (eyorn("No newline at end of file, add one") == TRUE) { - lnewline_at(lback(lpend), llength(lback(lpend))); - putc('\n', ffp); - } + if (eobnl) { + lnewline_at(lback(lpend), llength(lback(lpend))); + putc('\n', ffp); } return (FIOSUC); }
Re: About transient mark mode
Leonid's diff would seem to be an improvement on current behaviour, any objections to adding it to mg? Or comments/ok? Mark From openbsd-tech Tue Jun 11 15:16:29 2019 From: Leonid Bobrov Date: Tue, 11 Jun 2019 15:16:29 + To: openbsd-tech Subject: About transient mark mode Message-Id: <20190611151629.GA7591 () mazocomp ! lan> X-MARC-Message: https://marc.info/?l=openbsd-tech=156026622527096 Hi! If we don't have to follow what GNU Emacs is doing anyway, let's just change behavior of {beginning,end}-of-buffer to this instead of implementing a useless mode: Index: basic.c === RCS file: /cvs/src/usr.bin/mg/basic.c,v retrieving revision 1.48 diff -u -p -r1.48 basic.c --- basic.c 3 Jun 2019 16:26:30 - 1.48 +++ basic.c 11 Jun 2019 15:15:15 - @@ -124,7 +124,8 @@ forwchar(int f, int n) int gotobob(int f, int n) { - (void) setmark(f, n); + if (!curwp-w_markp) + (void) setmark(f, n); curwp-w_dotp = bfirstlp(curbp); curwp-w_doto = 0; curwp-w_rflag |= WFFULL; @@ -150,7 +151,8 @@ gotoeob(int f, int n) int ln; struct line *lp; - (void) setmark(f, n); + if (!curwp-w_markp) + (void) setmark(f, n); curwp-w_dotp = blastlp(curbp); curwp-w_doto = llength(curwp-w_dotp); curwp-w_dotline = curwp-w_bufp-b_lines; Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.114 diff -u -p -r1.114 mg.1 --- mg.16 Jun 2019 18:17:34 - 1.114 +++ mg.111 Jun 2019 15:15:15 - @@ -1,7 +1,7 @@ .\" $OpenBSD: mg.1,v 1.114 2019/06/06 18:17:34 jmc Exp $ .\" This file is in the public domain. .\" -.Dd $Mdocdate: June 6 2019 $ +.Dd $Mdocdate: June 11 2019 $ .Dt MG 1 .Os .Sh NAME @@ -408,6 +408,7 @@ Move cursor to the top of the buffer. A numeric argument .Va n will move n/10th of the way from the top. +Set mark at previous position if mark is not set. .It beginning-of-line Move cursor to the beginning of the line. .It blink-and-insert @@ -532,6 +533,7 @@ Move cursor to the end of the buffer. A numeric argument .Va n will move n/10th of the way from the end. +Set mark at previous position if mark is not set. .It end-of-line Move cursor to the end of the line. .It enlarge-window Index: region.c === RCS file: /cvs/src/usr.bin/mg/region.c,v retrieving revision 1.37 diff -u -p -r1.37 region.c --- region.c9 Sep 2016 06:05:51 - 1.37 +++ region.c11 Jun 2019 15:15:15 - @@ -405,6 +405,7 @@ markbuffer(int f, int n) { if (gotoeob(f,n) == FALSE) return (FALSE); + (void) clearmark(f, n); if (gotobob(f,n) == FALSE) return (FALSE); return (TRUE);
mg(1) log internals to file
This diff allows mg to log its internal status to a file. At the moment it only logs line information like front and back pointers in the linked list, how many characters are used and where the cursor is placed in the file, but I am finding it incredibly useful debugging mg at the moment. Below is an example log file after opening a file with this contents: abc def ghk After I open the file in mg, I move forward a line (C-n), then move forward a character (C-f): $ cat log/mg.log next-line 3 3 0xc3a3557ae00 b^0xc3a592eac20 f.0xc3a592ea4a0 abc 3 3 0xc3a592ea4a0 b^0xc3a3557ae00 f.0xc3a592ea660 def 3 3 0xc3a592ea660 b^0xc3a592ea4a0 f.0xc3a307830e0 ghk 0 0 0xc3a307830e0 b^0xc3a592ea660 f.0xc3a592eac20 (null) head 0xc3a592eac20 b^0xc3a307830e0 f.0xc3a3557ae00 (EOB) forward-char 3 3 0xc3a3557ae00 b^0xc3a592eac20 f.0xc3a592ea4a0 abc 3 3 0xc3a592ea4a0 b^0xc3a3557ae00 f.0xc3a592ea660 def 3 3 0xc3a592ea660 b^0xc3a592ea4a0 f.0xc3a307830e0 ghk 0 0 0xc3a307830e0 b^0xc3a592ea660 f.0xc3a592eac20 (null) head 0xc3a592eac20 b^0xc3a307830e0 f.0xc3a3557ae00 (EOB) The three columns of pointer addresses are (from the 'def' line): 0xc3a592ea4a0 the lines own pointer. 0xc3a3557ae00 the pointer to back(b^) line 0xc3a592ea660 the pointer to forward(f.) line The numbers at the start of the first four lines are l_size and l_used. With this diff logging is not switched on by default and has to compiled into mg. -DMGDEBUG has to be added to the Makefile: CFLAGS+=-Wall -DREGEX -DMGDEBUG And the comment removed from: #SRCS+= log.c The information logged at the moment is viewable by gdb, however, if a bug that I have introduced doesn't present itself for XX number of key presses, I can struggle to work out what has caused it in gdb, logging like this makes problems I have introduced much more obvious and easier to fix. I have tried to make the ifdefs as minimal as possible. Any objections to this diff? Mark Index: Makefile === RCS file: /cvs/src/usr.bin/mg/Makefile,v retrieving revision 1.33 diff -u -p -u -p -r1.33 Makefile --- Makefile16 Sep 2016 17:17:40 - 1.33 +++ Makefile7 Jun 2019 14:42:39 - @@ -9,6 +9,7 @@ DPADD+= ${LIBCURSES} ${LIBUTIL} # # REGEX -- create regular expression functions. # STARTUPFILE -- look for and handle initialization file. +# MGDEBUG -- debug mg internals to a log file. # CFLAGS+=-Wall -DREGEX @@ -22,6 +23,11 @@ SRCS=autoexec.c basic.c bell.c buffer.c # More or less standalone extensions. # SRCS+= cmode.c cscope.c dired.c grep.c tags.c + +# +# -DMGDEBUG source file. +# +#SRCS+=log.c afterinstall: ${INSTALL} -d -o root -g wheel ${DESTDIR}${DOCDIR}/mg Index: kbd.c === RCS file: /cvs/src/usr.bin/mg/kbd.c,v retrieving revision 1.30 diff -u -p -u -p -r1.30 kbd.c --- kbd.c 26 Sep 2015 21:51:58 - 1.30 +++ kbd.c 7 Jun 2019 14:42:39 - @@ -15,6 +15,10 @@ #include "key.h" #include "macro.h" +#ifdef MGDEBUG +#include "log.h" +#endif + #define METABIT 0x80 #define PROMPTL 80 @@ -151,6 +155,11 @@ doin(void) while ((funct = doscan(curmap, (key.k_chars[key.k_count++] = getkey(TRUE)), )) == NULL) /* nothing */; + +#ifdef MGDEBUG + if (!mglog(funct)) + ewprintf("Problem with logging"); +#endif if (macrodef && macrocount < MAXMACRO) macro[macrocount++].m_funct = funct; Index: log.c === RCS file: log.c diff -N log.c --- /dev/null 1 Jan 1970 00:00:00 - +++ log.c 7 Jun 2019 14:42:39 - @@ -0,0 +1,121 @@ +/* $OpenBSD$ */ + +/* + * This file is in the public domain. + * + * Author: Mark Lumsden + * + */ + +/* + * Record a history of an mg session for temporal debugging. + * Sometimes pressing a key will set the scene for a bug only visible + * dozens of keystrokes later. gdb has its limitations in this scenario. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "def.h" +#include "log.h" +#include "funmap.h" + +static charmglogpath[20]; + +int +mglog(PF funct) +{ + struct line *lp; + struct stat sb; + char*curline; + FILE*fd; + int i; + + i = 0; + + if(stat(mglogpath, )) + return (FALSE); + + fd = fopen(mglogpath, "a"); + if (fprintf(fd, "%s\n", function_name(funct)) == -1) { + fclose(fd); + return (FALSE); + } + lp = bfirstlp(curbp); + + for(;;) { + i++; + curline = " "; + if (i == curw
mg(1): {beginning,end}-of-buffer numeric argument
This diff gives the commands beginning-of-buffer and end-of-buffer the ability to take a numeric argument and move n/10th of the way from the top or bottom of the current buffer respectively. Any comments/testers/oks? Mark Index: basic.c === RCS file: /cvs/src/usr.bin/mg/basic.c,v retrieving revision 1.47 diff -u -p -u -p -r1.47 basic.c --- basic.c 10 Oct 2015 09:13:14 - 1.47 +++ basic.c 31 May 2019 11:16:58 - @@ -21,6 +21,8 @@ #include "def.h" +#define percint(n1, n2)((n1 * (int) n2) * 0.1) + /* * Go to beginning of line. */ @@ -127,6 +129,12 @@ gotobob(int f, int n) curwp->w_doto = 0; curwp->w_rflag |= WFFULL; curwp->w_dotline = 1; + if (f & FFOTHARG && n > 0) { + if (n > 9) + gotoeob(0, 0); + else + forwline(f, percint(curwp->w_bufp->b_lines, n) - 1); + } return (TRUE); } @@ -138,6 +146,7 @@ gotobob(int f, int n) int gotoeob(int f, int n) { + int ln; struct line *lp; (void) setmark(f, n); @@ -146,15 +155,22 @@ gotoeob(int f, int n) curwp->w_dotline = curwp->w_bufp->b_lines; lp = curwp->w_dotp; - n = curwp->w_ntrows - 3; + ln = curwp->w_ntrows - 3; - if (n < curwp->w_bufp->b_lines && n >= 3) { - while (n--) + if (ln < curwp->w_bufp->b_lines && ln >= 3) { + while (ln--) curwp->w_dotp = lback(curwp->w_dotp); curwp->w_linep = curwp->w_dotp; curwp->w_dotp = lp; } + if (f & FFOTHARG && n > 1) { + if (n > 9) + gotobob(0, 0); + else + backline(f, percint(curwp->w_bufp->b_lines, n)); + } + curwp->w_rflag |= WFFULL; return (TRUE); } Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.112 diff -u -p -u -p -r1.112 mg.1 --- mg.126 Dec 2018 07:01:22 - 1.112 +++ mg.131 May 2019 11:16:58 - @@ -405,6 +405,9 @@ Paragraphs are delimited by or Move cursor backwards by the specified number of words. .It beginning-of-buffer Move cursor to the top of the buffer. +A numeric argument +.Va n , +will move n/10th of the way from the top. .It beginning-of-line Move cursor to the beginning of the line. .It blink-and-insert @@ -526,6 +529,9 @@ version string. Stop defining a keyboard macro. .It end-of-buffer Move cursor to the end of the buffer. +A numeric argument +.Va n , +will move n/10th of the way from the end. .It end-of-line Move cursor to the end of the line. .It enlarge-window
Re: ssh-keygen: interactive comment change
On Wed, 22 May 2019, Mark Lumsden wrote: Date: Wed, 22 May 2019 18:49:23 + (UTC) From: Mark Lumsden To: tech@openbsd.org Subject: ssh-keygen: interactive comment change I used the -C command line option of ssh-keygen to change the comment of a public key and got confused with the output. For example, if the original comment was 'mark@home', this is what would happen trying to amend the comment to 'mark@work' via -C: $ ssh-keygen -f test_rsa -c -C mark@work Key now has comment 'mark@home' The comment in your key file has been changed. $ The line "Key now has comment 'mark@home'" suggested to me that the comment had been changed to 'mark@home'. But thats not really a change. However, the comment had actually changed in the .pub file. It looks like the wording has been designed to work without the -C option and _only_ the -c option: $ ssh-keygen -f test_rsa -c Key now has comment 'mark@home' Enter new comment: mark@work The comment in your key file has been changed. $ Everything becomes clear when you run the command interactively via -c only. The diff below attempts to make the wording make sense which ever way you try to change a comment on a .pub file: $ ssh-keygen -f test_rsa -c Old comment: mark@home New comment: mark@work Comment 'mark@work' applied $ $ ssh-keygen -f test_rsa -c -C mark@work Old comment: mark@home Comment 'mark@work' applied $ It also compares the old and new comments and informs if there is no change: $ ssh-keygen -f test_rsa -c -C mark@home Old comment: mark@home No change to comment $ $ ssh-keygen -f test_rsa -c Old comment: mark@work New comment: mark@work No change to comment $ ok? Mark Here is a better diff. It doesn't say that the public key has been written, until it has actually been written. If there is no change detected in the old and new comments, it doesn't try and write anything, just cleans up and exits. Index: ssh-keygen.c === RCS file: /cvs/src/usr.bin/ssh/ssh-keygen.c,v retrieving revision 1.329 diff -u -p -u -p -r1.329 ssh-keygen.c --- ssh-keygen.c25 Mar 2019 16:19:44 - 1.329 +++ ssh-keygen.c22 May 2019 19:40:49 - @@ -1466,15 +1466,15 @@ do_change_comment(struct passwd *pw, con sshkey_free(private); exit(1); } - if (comment) - printf("Key now has comment '%s'\n", comment); + if (strlen(comment) > 0) + printf("Old comment: %s\n", comment); else - printf("Key now has no comment\n"); + printf("No existing comment\n"); if (identity_comment) { strlcpy(new_comment, identity_comment, sizeof(new_comment)); } else { - printf("Enter new comment: "); + printf("New comment: "); fflush(stdout); if (!fgets(new_comment, sizeof(new_comment), stdin)) { explicit_bzero(passphrase, strlen(passphrase)); @@ -1483,6 +1483,13 @@ do_change_comment(struct passwd *pw, con } new_comment[strcspn(new_comment, "\n")] = '\0'; } + if (strcmp(comment, new_comment) == 0) { + printf("No change to comment\n"); + free(passphrase); + sshkey_free(private); + free(comment); + exit(0); + } /* Save the file using the new passphrase. */ if ((r = sshkey_save_private(private, identity_file, passphrase, @@ -1514,9 +1521,13 @@ do_change_comment(struct passwd *pw, con fprintf(f, " %s\n", new_comment); fclose(f); + if (strlen(new_comment) > 0) + printf("Comment '%s' applied\n", new_comment); + else + printf("Comment removed\n"); + free(comment); - printf("The comment in your key file has been changed.\n"); exit(0); }
ssh-keygen: interactive comment change
I used the -C command line option of ssh-keygen to change the comment of a public key and got confused with the output. For example, if the original comment was 'mark@home', this is what would happen trying to amend the comment to 'mark@work' via -C: $ ssh-keygen -f test_rsa -c -C mark@work Key now has comment 'mark@home' The comment in your key file has been changed. $ The line "Key now has comment 'mark@home'" suggested to me that the comment had been changed to 'mark@home'. But thats not really a change. However, the comment had actually changed in the .pub file. It looks like the wording has been designed to work without the -C option and _only_ the -c option: $ ssh-keygen -f test_rsa -c Key now has comment 'mark@home' Enter new comment: mark@work The comment in your key file has been changed. $ Everything becomes clear when you run the command interactively via -c only. The diff below attempts to make the wording make sense which ever way you try to change a comment on a .pub file: $ ssh-keygen -f test_rsa -c Old comment: mark@home New comment: mark@work Comment 'mark@work' applied $ $ ssh-keygen -f test_rsa -c -C mark@work Old comment: mark@home Comment 'mark@work' applied $ It also compares the old and new comments and informs if there is no change: $ ssh-keygen -f test_rsa -c -C mark@home Old comment: mark@home No change to comment $ $ ssh-keygen -f test_rsa -c Old comment: mark@work New comment: mark@work No change to comment $ ok? Mark Index: ssh-keygen.c === RCS file: /cvs/src/usr.bin/ssh/ssh-keygen.c,v retrieving revision 1.329 diff -u -p -u -p -r1.329 ssh-keygen.c --- ssh-keygen.c25 Mar 2019 16:19:44 - 1.329 +++ ssh-keygen.c22 May 2019 18:21:42 - @@ -1466,15 +1466,15 @@ do_change_comment(struct passwd *pw, con sshkey_free(private); exit(1); } - if (comment) - printf("Key now has comment '%s'\n", comment); + if (strlen(comment) > 0) + printf("Old comment: %s\n", comment); else - printf("Key now has no comment\n"); + printf("No existing comment\n"); if (identity_comment) { strlcpy(new_comment, identity_comment, sizeof(new_comment)); } else { - printf("Enter new comment: "); + printf("New comment: "); fflush(stdout); if (!fgets(new_comment, sizeof(new_comment), stdin)) { explicit_bzero(passphrase, strlen(passphrase)); @@ -1483,6 +1483,12 @@ do_change_comment(struct passwd *pw, con } new_comment[strcspn(new_comment, "\n")] = '\0'; } + if (strcmp(comment, new_comment) == 0) + printf("No change to comment\n"); + else if (strlen(new_comment) > 0) + printf("Comment '%s' applied\n", new_comment); + else + printf("Comment removed\n"); /* Save the file using the new passphrase. */ if ((r = sshkey_save_private(private, identity_file, passphrase, @@ -1516,7 +1522,6 @@ do_change_comment(struct passwd *pw, con free(comment); - printf("The comment in your key file has been changed.\n"); exit(0); }
Re: mg: Delete region
On Sun, 23 Dec 2018, Hiltjo Posthuma wrote: Date: Sun, 23 Dec 2018 13:43:32 +0100 From: Hiltjo Posthuma To: Mark Lumsden Cc: Leonid Bobrov , tech@openbsd.org Subject: Re: mg: Delete region On Thu, Dec 20, 2018 at 06:44:15AM +, Mark Lumsden wrote: hmm, you are correct. I'm trying to remember which machine I tested on that made me come to that conclusion. On Thu, 20 Dec 2018, Leonid Bobrov wrote: Date: Thu, 20 Dec 2018 06:43:02 +0200 From: Leonid Bobrov To: Mark Lumsden , tech@openbsd.org Subject: Re: mg: Delete region I tried this in GNU Emacs and it didn't place the killed region into the kill buffer. It only places it into the kill buffer if you pressed C-w Hi, Can this change get reverted upstream until it is properly tested (and OK'd), please? -- Kind regards, Hiltjo Its should be trivial to make it behave as emacs does. I should get time in about a week to have a look. Personally I don't think it needs reverted since it is more useful having it behave as it does just now than previously. But if someone wants to do so they are free to do that.
Re: mg: Delete region
hmm, you are correct. I'm trying to remember which machine I tested on that made me come to that conclusion. On Thu, 20 Dec 2018, Leonid Bobrov wrote: Date: Thu, 20 Dec 2018 06:43:02 +0200 From: Leonid Bobrov To: Mark Lumsden , tech@openbsd.org Subject: Re: mg: Delete region I tried this in GNU Emacs and it didn't place the killed region into the kill buffer. It only places it into the kill buffer if you pressed C-w
mg: Delete region
Currently in mg, if the cursor is in a region and the 'delete' or 'backspace' keys are pressed mg will not behave any differently than if the cursor wasn't in a region. The diff below makes mg behave like emacs and kills the region and places it into the kill buffer. ok? Mark Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.109 diff -u -p -u -p -r1.109 mg.1 --- mg.113 Dec 2018 14:59:16 - 1.109 +++ mg.117 Dec 2018 16:34:41 - @@ -475,6 +475,8 @@ Delete backwards characters. Like delete-char, this actually does a kill if presented with an argument. +If the cursor is in a region, the region is removed and placed +in to the kill buffer. .It delete-blank-lines Delete blank lines around dot. If dot is sitting on a blank line, this command @@ -486,6 +488,8 @@ Delete characters forward. If any argument is present, it kills rather than deletes, saving the result in the kill buffer. +If the cursor is in a region, the region is removed and placed +in to the kill buffer. .It delete-horizontal-space Delete any whitespace around the dot. .It delete-leading-space Index: util.c === RCS file: /cvs/src/usr.bin/mg/util.c,v retrieving revision 1.38 diff -u -p -u -p -r1.38 util.c --- util.c 18 Nov 2015 18:21:06 - 1.38 +++ util.c 17 Dec 2018 16:34:41 - @@ -411,7 +411,8 @@ indent(int f, int n) * Delete forward. This is real easy, because the basic delete routine does * all of the work. Watches for negative arguments, and does the right thing. * If any argument is present, it kills rather than deletes, to prevent loss - * of text if typed with a big argument. Normally bound to "C-D". + * of text if typed with a big argument. Normally bound to "C-d". + * If the cursor is in a region, kill the region. */ /* ARGSUSED */ int @@ -420,6 +421,9 @@ forwdel(int f, int n) if (n < 0) return (backdel(f | FFRAND, -n)); + if (curwp->w_markp != NULL) + return(killregion(FFRAND, 1)); + /* really a kill */ if (f & FFARG) { if ((lastflag & CFKILL) == 0) @@ -434,6 +438,7 @@ forwdel(int f, int n) * Delete backwards. This is quite easy too, because it's all done with * other functions. Just move the cursor back, and delete forwards. Like * delete forward, this actually does a kill if presented with an argument. + * If the cursor is in a region, kill the region. */ /* ARGSUSED */ int @@ -443,6 +448,9 @@ backdel(int f, int n) if (n < 0) return (forwdel(f | FFRAND, -n)); + + if (curwp->w_markp != NULL) + return (killregion(FFRAND, 1)); /* really a kill */ if (f & FFARG) {
mg: toggle-read-only-all
Allow all non-ephemeral buffers to be toggled write/read-only. This toggle works while mg is running, unlike the -R option which is only during mg startup. ok? Index: buffer.c === RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.104 diff -u -p -u -p -r1.104 buffer.c --- buffer.c6 Aug 2017 04:39:45 - 1.104 +++ buffer.c27 Nov 2018 19:52:41 - @@ -31,6 +31,28 @@ extern int globalwd; /* ARGSUSED */ int +togglereadonlyall(int f, int n) +{ + struct buffer *bp = NULL; + int len = 0; + + allbro = !allbro; + for (bp = bheadp; bp != NULL; bp = bp->b_bufp) { + len = strlen(bp->b_bname); + if (bp->b_bname[0] != '*' && bp->b_bname[len - 1] != '*') { + if (allbro) + bp->b_flag |= BFREADONLY; + else + bp->b_flag &= ~BFREADONLY; + } + } + curwp->w_rflag |= WFMODE; + + return (TRUE); +} + +/* ARGSUSED */ +int togglereadonly(int f, int n) { int s; Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.156 diff -u -p -u -p -r1.156 def.h --- def.h 29 Aug 2018 07:50:16 - 1.156 +++ def.h 27 Nov 2018 19:52:41 - @@ -417,6 +417,7 @@ int delwind(int, int); /* buffer.c */ int togglereadonly(int, int); +int togglereadonlyall(int, int); struct buffer *bfind(const char *, int); int poptobuffer(int, int); int killbuffer(struct buffer *); @@ -737,6 +738,7 @@ extern int defb_flag; extern int doaudiblebell; extern int dovisiblebell; extern int dblspace; +extern int allbro; extern char cinfo[]; extern char*keystrings[]; extern char pat[NPAT]; Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.54 diff -u -p -u -p -r1.54 funmap.c --- funmap.c29 Aug 2018 07:50:16 - 1.54 +++ funmap.c27 Nov 2018 19:52:41 - @@ -201,6 +201,7 @@ static struct funmap functnames[] = { {usebuffer, "switch-to-buffer",}, {poptobuffer, "switch-to-buffer-other-window",}, {togglereadonly, "toggle-read-only" }, + {togglereadonlyall, "toggle-read-only-all" }, {twiddle, "transpose-chars",}, {transposepara, "transpose-paragraphs",}, {transposeword, "transpose-words",}, Index: main.c === RCS file: /cvs/src/usr.bin/mg/main.c,v retrieving revision 1.84 diff -u -p -u -p -r1.84 main.c --- main.c 16 Sep 2016 17:17:40 - 1.84 +++ main.c 27 Nov 2018 19:52:41 - @@ -28,6 +28,7 @@ intstartrow; /* row to start */ int doaudiblebell; /* audible bell toggle */ int dovisiblebell; /* visible bell toggle */ int dblspace; /* sentence end #spaces */ +int allbro;/* all buffs read-only */ struct buffer *curbp; /* current buffer */ struct buffer *bheadp;/* BUFFER list head */ struct mgwin *curwp; /* current window */ @@ -65,6 +66,7 @@ main(int argc, char **argv) switch (o) { case 'R': bro = 1; + allbro = 1; break; case 'n': nobackups = 1; Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.108 diff -u -p -u -p -r1.108 mg.1 --- mg.118 Nov 2018 07:57:28 - 1.108 +++ mg.127 Nov 2018 19:52:41 - @@ -884,6 +884,10 @@ Prompt and switch to a new buffer in the Switch to buffer in another window. .It toggle-read-only Toggle the read-only flag on the current buffer. +.It toggle-read-only-all +Toggle the read-only flag on all non-ephemeral buffers. +A simple toggle that switches a global read-only flag either on +or off. .It transpose-chars Transpose the two characters in front of and under dot, then move forward one character.
mg and \n char
Hi, I'm trying to work out a way of progressing mg to be 8 bit clean. Not being 100% sure of the scope of the problem and solution, attached is a diff that is trying to remove the implied or faked '\n' character from mg's buffers. I'm taking the approach of loading the '\n' char from disk to buffer, instead of removing it at buffer load time (when opening a file) as mg does at the moment. This diff only fixes 20% of the ramifications of doing that, so if you apply the diff mg will be very buggy afterwards, but this diff is only trying to discuss the approach of going 8 bit clean and how to acheive that. If removing the implied '\n' character this way is deemed suitable then I can carry on cleaning up the other 80% so that the main functionality of mg is not affected with not having an implied \n or a faked \n but having a 'real' \n on a new-line in a buffer. One of the changes in having a \n at the end of a line is how mg works with the length of a line. Some functions need to know the new length (+1 char) but some others don't. For example, if you C-e to the end of a line, currently mg leaves the cursor where a \n should be and says the cursor is on X column. If you then M-x what-cursor-position, mg fakes a \n character and tells you a \n is under the cursor. With the attached diff, if you C-e to the end of a line, the function called via C-e (gotoeol), puts the cursor on the length of the displayed line, which is 1 less than the 'real' length of the line, which now includes a \n char. If you then M-x what-cursor-position, mg will report the cursor is on a \n character because it _is_ on a \n character. I've introduced a new version of llength(): #define llength(lp)((lp)->l_used) /* real line length */ #define dis_llength(lp)(llength(lp) - 1) /* displayed line length */ However, is this approach the right way to progress 8 bit cleaness? I am no sure, please feel free to express your opinion. Also, is anyone else working on this? Mark Index: basic.c === RCS file: /cvs/src/usr.bin/mg/basic.c,v retrieving revision 1.47 diff -u -p -r1.47 basic.c --- basic.c 10 Oct 2015 09:13:14 - 1.47 +++ basic.c 15 Nov 2018 08:00:03 - @@ -59,7 +59,7 @@ backchar(int f, int n) return (FALSE); } curwp->w_dotp = lp; - curwp->w_doto = llength(lp); + curwp->w_doto = dis_llength(lp); curwp->w_rflag |= WFMOVE; curwp->w_dotline--; } else @@ -78,7 +78,8 @@ gotoeol(int f, int n) if (n == 0) return (TRUE); - curwp->w_doto = llength(curwp->w_dotp); + /* need to check if line is end of buffer and no '\n'*/ + curwp->w_doto = dis_llength(curwp->w_dotp); return (TRUE); } @@ -95,7 +96,7 @@ forwchar(int f, int n) if (n < 0) return (backchar(f, -n)); while (n--) { - if (curwp->w_doto == llength(curwp->w_dotp)) { + if (curwp->w_doto == dis_llength(curwp->w_dotp)) { curwp->w_dotp = lforw(curwp->w_dotp); if (curwp->w_dotp == curbp->b_headp) { curwp->w_dotp = lback(curwp->w_dotp); @@ -142,7 +143,7 @@ gotoeob(int f, int n) (void) setmark(f, n); curwp->w_dotp = blastlp(curbp); - curwp->w_doto = llength(curwp->w_dotp); + curwp->w_doto = llength(curwp->w_dotp);/* check no '\n'!! */ curwp->w_dotline = curwp->w_bufp->b_lines; lp = curwp->w_dotp; @@ -190,7 +191,8 @@ forwline(int f, int n) dlp = lforw(dlp); if (dlp == curbp->b_headp) { curwp->w_dotp = lback(dlp); - curwp->w_doto = llength(curwp->w_dotp); + /*check if end of buffer and no '\n'*/ + curwp->w_doto = dis_llength(curwp->w_dotp); curwp->w_rflag |= WFMOVE; if (!(f & FFRAND)) { dobeep(); @@ -275,7 +277,9 @@ getgoal(struct line *dlp) for (i = 0; i < llength(dlp); i++) { c = lgetc(dlp, i); - if (c == '\t' + if (c == '\n') + ; /* check working */ + else if (c == '\t' #ifdef NOTAB && !(curbp->b_flag & BFNOTAB) #endif Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.156 diff -u -p -r1.156 def.h --- def.h 29 Aug 2018 07:50:16 - 1.156 +++ def.h 15 Nov 2018 08:00:03 - @@ -150,7 +150,8 @@ struct line { #define lback(lp) ((lp)->l_bp) #define lgetc(lp, n) (CHARMASK((lp)->l_text[(n)])) #define lputc(lp, n, c) ((lp)->l_text[(n)]=(c))
mg: fix undo transpose-paragraph
Currently undoing transpose-paragraph doesn't work as expected. This diff fixes that. ok? Index: paragraph.c === RCS file: /cvs/src/usr.bin/mg/paragraph.c,v retrieving revision 1.45 diff -u -p -r1.45 paragraph.c --- paragraph.c 6 Sep 2016 16:25:47 - 1.45 +++ paragraph.c 13 Nov 2018 21:20:48 - @@ -338,6 +338,8 @@ transposepara(int f, int n) if (n == 0) return (TRUE); + undo_boundary_enable(FFRAND, 0); + /* find a paragraph, set mark, then goto the end */ gotobop(FFRAND, 1); curwp->w_markp = curwp->w_dotp; @@ -364,6 +366,8 @@ transposepara(int f, int n) return (FALSE); } (void)yank(FFRAND, 1); + + undo_boundary_enable(FFRAND, 1); return (TRUE); }
Re: mg docs ownership
> Maybe we should just not install it? Mark? A couple of years ago when the tutorial started being installed there were no dissenting voices, so unless there are objections, I'd carry on doing that. And Martin's diff makes sense I think. Mark
mg: region.c:preadin() - Also check for read() error
Source Joachim Nilsson: Coverity Scan found this interesting buglet. If read() fails the code, before this patch, would trigger a "Negative array index write". ok? Index: region.c === RCS file: /cvs/src/usr.bin/mg/region.c,v retrieving revision 1.36 diff -u -p -u -p -r1.36 region.c --- region.c8 Sep 2016 07:50:09 - 1.36 +++ region.c8 Sep 2016 07:56:14 - @@ -650,7 +650,7 @@ preadin(int fd, struct buffer *bp) int len; char buf[BUFSIZ], *p, *q; - if ((len = read(fd, buf, BUFSIZ - 1)) == 0) + if ((len = read(fd, buf, BUFSIZ - 1)) <= 0) return (FALSE); buf[len] = '\0';
mg - Check pointer before calling showbuffer()
Source Joachim Nilsson: Found by Coverity Scan. The popbuf() function iterated over a list to find a wp pointer, then sent it to showbuffer() which immediately went ahead and dereferenced it. This patch simply adds a NULL pointer check before calling showbuffer(), if NULL then just return NULL to callee. The missing NULL check is actually referenced in a comment a few lines earlier in the code. ok? -lum Index: buffer.c === RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.101 diff -u -p -u -p -r1.101 buffer.c --- buffer.c31 Aug 2016 12:22:28 - 1.101 +++ buffer.c6 Sep 2016 17:04:22 - @@ -713,12 +713,16 @@ popbuf(struct buffer *bp, int flags) while (wp != NULL && wp == curwp) wp = wp->w_wndp; - } else + } else { for (wp = wheadp; wp != NULL; wp = wp->w_wndp) if (wp->w_bufp == bp) { wp->w_rflag |= WFFULL | WFFRAME; return (wp); } + } + if (!wp) + return (NULL); + if (showbuffer(bp, wp, WFFULL) != TRUE) return (NULL); return (wp);
mg: goto end of para @ end of buffer problem
Currently in mg, if you have a paragraph: 123 456 With the cursor on either the 4, 5 or 6 and no newline after the '6', and then execute forward-paragraph (M-}), the cursor sits still and does not move to the end of second line (after the 6), which is in effect the end of parapraph. This diff fixes that behaviour. ok? -lum Index: paragraph.c === RCS file: /cvs/src/usr.bin/mg/paragraph.c,v retrieving revision 1.44 diff -u -p -u -p -r1.44 paragraph.c --- paragraph.c 14 Apr 2016 17:05:32 - 1.44 +++ paragraph.c 5 Sep 2016 14:34:45 - @@ -108,13 +108,13 @@ do_gotoeop(int f, int n, int *i) curwp->w_dotp = lforw(curwp->w_dotp); curwp->w_dotline++; - /* do not continue after end of buffer */ - if (lforw(curwp->w_dotp) == curbp->b_headp) { - gotoeol(FFRAND, 1); - curwp->w_rflag |= WFMOVE; - return (FALSE); - } } + } + /* do not continue after end of buffer */ + if (lforw(curwp->w_dotp) == curbp->b_headp) { + gotoeol(FFRAND, 1); + curwp->w_rflag |= WFMOVE; + return (FALSE); } /* force screen update */
mg(1) Initialize stack variables to zero before memmove()
Source Joachim Nilsson: Coverity Scan reported these two stack variables as uninitialized, in particular the .r_lineno struct member was uninitialized. This patch clears the 'struct region' rather than setting .r_lineno because if any more struct members are added in the future the clear will cover them too. I think Joachim's approach is sensible. ok? -lum Index: undo.c === RCS file: /cvs/src/usr.bin/mg/undo.c,v retrieving revision 1.57 diff -u -p -u -p -r1.57 undo.c --- undo.c 11 Dec 2015 20:21:23 - 1.57 +++ undo.c 2 Sep 2016 07:02:18 - @@ -269,6 +269,8 @@ undo_add_insert(struct line *lp, int off if (!undo_enable_flag) return (TRUE); + + memset(, 0, sizeof(reg)); reg.r_linep = lp; reg.r_offset = offset; reg.r_size = size; @@ -315,6 +317,7 @@ undo_add_delete(struct line *lp, int off if (!undo_enable_flag) return (TRUE); + memset(, 0, sizeof(reg)); reg.r_linep = lp; reg.r_offset = offset; reg.r_size = size;
Re: mg - sentence-end-double-space
Hi Ingo, On Tue, Apr 12, 2016 at 08:39:07PM +0200, Ingo Schwarze wrote: > Hi Mark, > > Mark Lumsden wrote on Tue, Apr 12, 2016 at 06:47:40PM +: > > > This diff allows a single space for sentence delimitation. > > ok/comments/objections? > > No objection, but a comment. Note that *using* the option is > destructive. Once you have replaced double spaces at the ends > of sentences with single spaces, there is no algorithm short of > computer linguistics that can take you back, because with that > change, abbreviations become indistinguishable from full stops. > You are correct though there is "undo". > You might or might not want to mention that in the manual - > depending on whether you consider it more important to prevent > people from hurting themselves or to keep the manual concise. > I think conciseness is more important here. Thanks for the comments. mark
mg - sentence-end-double-space
This diff allows a single space for sentence delimitation. ok/comments/objections? The default of a double space is left as is. mark Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.154 diff -u -p -u -p -r1.154 def.h --- def.h 2 Jan 2016 10:39:19 - 1.154 +++ def.h 12 Apr 2016 18:01:57 - @@ -593,6 +593,7 @@ int fillword(int, int); int setfillcol(int, int); int markpara(int, int); int transposepara(int, int); +int sentencespace(int, int); /* word.c X */ int backword(int, int); @@ -734,6 +735,7 @@ extern int defb_nmodes; extern int defb_flag; extern int doaudiblebell; extern int dovisiblebell; +extern int dblspace; extern char cinfo[]; extern char*keystrings[]; extern char pat[NPAT]; Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.52 diff -u -p -u -p -r1.52 funmap.c --- funmap.c29 Dec 2015 19:44:32 - 1.52 +++ funmap.c12 Apr 2016 18:01:57 - @@ -180,6 +180,7 @@ static struct funmap functnames[] = { {backsearch, "search-backward",}, {forwsearch, "search-forward",}, {selfinsert, "self-insert-command",}, + {sentencespace, "sentence-end-double-space",}, #ifdef REGEX {setcasefold, "set-case-fold-search",}, #endif /* REGEX */ Index: main.c === RCS file: /cvs/src/usr.bin/mg/main.c,v retrieving revision 1.81 diff -u -p -u -p -r1.81 main.c --- main.c 24 Dec 2015 09:07:47 - 1.81 +++ main.c 12 Apr 2016 18:01:57 - @@ -27,6 +27,7 @@ intcurgoal; /* goal column */ int startrow; /* row to start */ int doaudiblebell; /* audible bell toggle */ int dovisiblebell; /* visible bell toggle */ +int dblspace; /* sentence end #spaces */ struct buffer *curbp; /* current buffer */ struct buffer *bheadp;/* BUFFER list head */ struct mgwin *curwp; /* current window */ @@ -109,6 +110,7 @@ main(int argc, char **argv) edinit(bp); /* Buffers, windows.*/ ttykeymapinit();/* Symbols, bindings. */ bellinit(); /* Audible and visible bell.*/ + dblspace = 1; /* two spaces for sentence end. */ /* * doing update() before reading files causes the error messages from Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.103 diff -u -p -u -p -r1.103 mg.1 --- mg.117 Mar 2016 21:56:12 - 1.103 +++ mg.112 Apr 2016 18:01:58 - @@ -838,6 +838,10 @@ If found, dot gets moved to just after t characters, if not found, print a message. .It self-insert-command Insert a character. +.It sentence-end-double-space +Toggle double or single spaces for end of sentences. +Double is the default. +Currently only affects fill-paragraph. .It set-case-fold-search Set case-fold searching, causing case not to matter in regular expression searches. Index: paragraph.c === RCS file: /cvs/src/usr.bin/mg/paragraph.c,v retrieving revision 1.43 diff -u -p -u -p -r1.43 paragraph.c --- paragraph.c 12 Apr 2016 06:20:50 - 1.43 +++ paragraph.c 12 Apr 2016 18:01:58 - @@ -208,12 +208,12 @@ fillpara(int f, int n) * behave the same way if a ')' is preceded by a * [.?!] and followed by a doublespace. */ - if (!eopflag && ((eolflag || + if (dblspace && (!eopflag && ((eolflag || curwp->w_doto == llength(curwp->w_dotp) || (c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || c == '\t') && (ISEOSP(wbuf[wordlen - 1]) || (wbuf[wordlen - 1] == ')' && wordlen >= 2 && - ISEOSP(wbuf[wordlen - 2]))) && + ISEOSP(wbuf[wordlen - 2] && wordlen < MAXWORD - 1)) wbuf[wordlen++] = ' '; @@ -480,5 +480,16 @@ setfillcol(int f, int n) fillcol = nfill; ewprintf("Fill column set to %d", fillcol); } + return (TRUE); +} + +int +sentencespace(int f, int n) +{ + if (f & FFARG) + dblspace = n > 1; + else
Bug#812810: fill-paragraph: Leaves a space at the end of the paragraph
This diff changes mg's behaviour to not put a space at the end of a paragraph when using the fill-paragraph function as reported by Harald Dunkel. ok/comments? Index: paragraph.c === RCS file: /cvs/src/usr.bin/mg/paragraph.c,v retrieving revision 1.42 diff -u -p -u -p -r1.42 paragraph.c --- paragraph.c 14 Dec 2015 03:25:59 - 1.42 +++ paragraph.c 3 Apr 2016 19:45:19 - @@ -208,13 +208,13 @@ fillpara(int f, int n) * behave the same way if a ')' is preceded by a * [.?!] and followed by a doublespace. */ - if ((eolflag || + if (!eopflag && ((eolflag || curwp->w_doto == llength(curwp->w_dotp) || (c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || c == '\t') && (ISEOSP(wbuf[wordlen - 1]) || (wbuf[wordlen - 1] == ')' && wordlen >= 2 && ISEOSP(wbuf[wordlen - 2]))) && - wordlen < MAXWORD - 1) + wordlen < MAXWORD - 1)) wbuf[wordlen++] = ' '; /* at a word break with a word waiting */
mg(1) dired-find-alternate-file
By shuffling find-alternate-file around we have dired-find-alternate-file as well. ok? -lum Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.153 diff -u -p -u -p -r1.153 def.h --- def.h 29 Dec 2015 19:44:32 - 1.153 +++ def.h 30 Dec 2015 13:20:35 - @@ -377,6 +377,7 @@ int makebkfile(int, int); int writeout(FILE **, struct buffer *, char *); voidupmodes(struct buffer *); size_t xbasename(char *, const char *, size_t); +int do_filevisitalt(char *); /* line.c X */ struct line*lalloc(int); Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.81 diff -u -p -u -p -r1.81 dired.c --- dired.c 11 Dec 2015 20:21:23 - 1.81 +++ dired.c 30 Dec 2015 13:20:35 - @@ -51,6 +51,7 @@ static int d_forwline(int, int); static int d_backline(int, int); static int d_killbuffer_cmd(int, int); static int d_refreshbuffer(int, int); +static int d_filevisitalt(int, int); static void reaper(int); static struct buffer *refreshbuffer(struct buffer *); static int createlist(struct buffer *); @@ -120,7 +121,9 @@ static PF diredcz[] = { d_create_directory /* + */ }; -static PF diredc[] = { +static PF direda[] = { + d_filevisitalt, /* a */ + rescan, /* b */ d_copy, /* c */ d_del, /* d */ d_findfile, /* e */ @@ -184,7 +187,7 @@ static struct KEYMAPE (7) diredmap = { CCHR('Z'), '+', diredcz, (KEYMAP *) & metamap }, { - 'c', 'g', diredc, NULL + 'a', 'g', direda, NULL }, { 'n', 'x', diredn, NULL @@ -838,6 +841,17 @@ d_backline (int f, int n) { backline(f | FFRAND, n); return (d_warpdot(curwp->w_dotp, >w_doto)); +} + +int +d_filevisitalt (int f, int n) +{ + char fname[NFILEN]; + + if (d_makename(curwp->w_dotp, fname, sizeof(fname)) == ABORT) + return (FALSE); + + return(do_filevisitalt(fname)); } /* Index: file.c === RCS file: /cvs/src/usr.bin/mg/file.c,v retrieving revision 1.99 diff -u -p -u -p -r1.99 file.c --- file.c 29 Oct 2015 19:46:47 - 1.99 +++ file.c 30 Dec 2015 13:20:35 - @@ -94,9 +94,7 @@ filevisit(int f, int n) int filevisitalt(int f, int n) { - struct buffer *bp; - char fname[NFILEN], *bufp, *adjf; - int status; + char fname[NFILEN], *bufp, *fn; if (getbufcwd(fname, sizeof(fname)) != TRUE) fname[0] = '\0'; @@ -107,11 +105,23 @@ filevisitalt(int f, int n) else if (bufp[0] == '\0') return (FALSE); + fn = fname; + + return (do_filevisitalt(fn)); +} + +int +do_filevisitalt(char *fn) +{ + struct buffer *bp; + int status; + char*adjf; + status = killbuffer(curbp); if (status == ABORT || status == FALSE) return (ABORT); - adjf = adjustname(fname, TRUE); + adjf = adjustname(fn, TRUE); if (adjf == NULL) return (FALSE); if (fisdir(adjf) == TRUE) Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.99 diff -u -p -u -p -r1.99 mg.1 --- mg.129 Dec 2015 19:44:32 - 1.99 +++ mg.130 Dec 2015 13:20:35 - @@ -952,6 +952,8 @@ dired-next-line dired-shell-command .It + dired-create-directory +.It a +dired-find-alternate-file .It c dired-do-copy .It d and C-d @@ -988,6 +990,9 @@ Copy the file listed on the current line Delete the files that have been flagged for deletion. .It dired-do-rename Rename the file listed on the current line of the dired buffer. +.It dired-find-alternate-file +Replace the current dired buffer with an alternate one as specified +by the position of the cursor. .It dired-find-file Open the file on the current line of the dired buffer. If the cursor is on a directory it will be opened in dired mode.
mg(1) tranpose-words
This diff adds transpose-words to mg. It behaves slightly differently from emacs when it comes to muliple iterations. Take this text for example: abc def ghi jkl mno pqr If the cursor is on the 'd', then you do C-u 3 M-t, in emacs the result will be: abc ghi jkl mno def pqr The attached diff gives this result in mg: abc ghi jkl mno def pqr Which personally I think is better. Also in emacs if you have this situation: 123 456 789 abc def ghi jkl mno pqr And the cursor is on 'a', then you do C-u 3 M-t, the result will be: 123 456 abc def ghi 789 jkl mno pqr Which I find quite zany when compared to the first example. The attached diff for mg does this: 123 456 abc def ghi 789 jkl mno pqr Which makes more sense to me but perhaps it is just as zany... What do people think? Mark Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.152 diff -u -p -u -p -r1.152 def.h --- def.h 29 Oct 2015 19:46:47 - 1.152 +++ def.h 24 Dec 2015 09:27:00 - @@ -602,6 +602,7 @@ int capword(int, int); int delfword(int, int); int delbword(int, int); int inword(void); +int transposeword(int, int); /* region.c X */ int killregion(int, int); Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.51 diff -u -p -u -p -r1.51 funmap.c --- funmap.c26 Sep 2015 15:03:15 - 1.51 +++ funmap.c24 Dec 2015 09:27:00 - @@ -201,6 +201,7 @@ static struct funmap functnames[] = { {togglereadonly, "toggle-read-only" }, {twiddle, "transpose-chars",}, {transposepara, "transpose-paragraphs",}, + {transposeword, "transpose-words",}, {undo, "undo",}, {undo_add_boundary, "undo-boundary",}, {undo_boundary_enable, "undo-boundary-toggle",}, Index: keymap.c === RCS file: /cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.57 diff -u -p -u -p -r1.57 keymap.c --- keymap.c26 Sep 2015 21:51:58 - 1.57 +++ keymap.c24 Dec 2015 09:27:00 - @@ -282,7 +282,7 @@ static PF metal[] = { fillpara, /* q */ backsearch, /* r */ forwsearch, /* s */ - rescan, /* t */ + transposeword, /* t */ upperword, /* u */ backpage, /* v */ copyregion, /* w */ Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.98 diff -u -p -u -p -r1.98 mg.1 --- mg.124 Dec 2015 09:07:47 - 1.98 +++ mg.124 Dec 2015 09:27:00 - @@ -306,6 +306,8 @@ fill-paragraph search-backward .It M-s search-forward +.It M-t +transpose-words .It M-u upcase-word .It M-v @@ -881,6 +883,12 @@ If multiple iterations are requested, th be moved .Va n paragraphs forward. +.It transpose-words +Transpose adjacent words. +If multiple iterations are requested, the current word will +be moved +.Va n +words forward. .It undo Undo the most recent action. If invoked again without an intervening command, Index: word.c === RCS file: /cvs/src/usr.bin/mg/word.c,v retrieving revision 1.17 diff -u -p -u -p -r1.17 word.c --- word.c 19 Mar 2015 21:22:15 - 1.17 +++ word.c 24 Dec 2015 09:27:00 - @@ -10,11 +10,15 @@ #include #include +#include #include +#include +#include #include "def.h" RSIZE countfword(void); +intgrabword(char **); /* * Move the cursor backward by "n" words. All of the details of motion are @@ -61,6 +65,158 @@ forwword(int f, int n) return (TRUE); } } + return (TRUE); +} + +/* + * Transpose 2 words. + */ +int +transposeword(int f, int n) +{ + struct line *tmp1_w_dotp = NULL; + struct line *tmp2_w_dotp = NULL; + int tmp2_w_doto = 0; + int tmp1_w_dotline = 0; + int tmp2_w_dotline = 0; + int tmp1_w_doto; + int i; /* start-of-line space counter */ + int ret, s; + int newline; + int leave = 0; + int tmp_len; + char*word1 = NULL; + char*word2 = NULL; + char*chr; + + if (n == 0) + return (TRUE); + + if ((s = checkdirty(curbp)) != TRUE) + return (s); + if (curbp->b_flag & BFREADONLY) { + dobeep(); + ewprintf("Buffer is read-only"); + return (FALSE); + } + + undo_boundary_enable(FFRAND, 0); +
mg - set read-only from command line
If I am opening a lot of files into an editor but with the intention of not changing the contents (or more usually only amending a couple of files), a la: > mg * I like to open them all read-only, then change the ones I want to edit to read-write as required, that way I know when I close them all I know that any changes are there because I wanted to make them. Instead of thinking 'did I really want that change' when I'm asked to save a file I didn't want to edit, but edited it accidentally. This diff allows mg to open all command specified files read-only: > mg -R * ok? Mark Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.96 diff -u -p -r1.96 mg.1 --- mg.121 Dec 2015 09:04:52 - 1.96 +++ mg.123 Dec 2015 15:53:03 - @@ -10,6 +10,7 @@ .Sh SYNOPSIS .Nm mg .Op Fl n +.Op Fl R .Op Fl f Ar mode .Op + Ns Ar number .Op Ar @@ -40,6 +41,8 @@ arguments on the command line, including scratch buffer and all files. .It Fl n Turn off backup file generation. +.It Fl R +Files specified on the command line will be opened read-only. .El .Sh WINDOWS AND BUFFERS When a file is loaded into Index: main.c === RCS file: /cvs/src/usr.bin/mg/main.c,v retrieving revision 1.80 diff -u -p -r1.80 main.c --- main.c 19 Nov 2015 19:30:44 - 1.80 +++ main.c 23 Dec 2015 15:53:03 - @@ -53,14 +53,17 @@ main(int argc, char **argv) char*cp, *init_fcn_name = NULL; PF init_fcn = NULL; int o, i, nfiles; - int nobackups = 0; + int nobackups = 0, bro = 0; struct buffer *bp = NULL; if (pledge("stdio rpath wpath cpath fattr getpw tty proc exec", NULL) == -1) err(1, "pledge"); - while ((o = getopt(argc, argv, "nf:")) != -1) + while ((o = getopt(argc, argv, "Rnf:")) != -1) switch (o) { + case 'R': + bro = 1; + break; case 'n': nobackups = 1; break; @@ -170,6 +173,8 @@ notnum: init_fcn(FFOTHARG, 1); nfiles++; } + if (bro) + curbp->b_flag |= BFREADONLY; } } }
mg(1) dired sort
This diff allows dired mode to sort directory contents alphabetically or by date order. It uses the same key as emacs: 's', though the extended command name is 'dired-sort'. Comments/ok? -lum Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.78 diff -u -p -u -p -r1.78 dired.c --- dired.c 12 Oct 2015 19:08:39 - 1.78 +++ dired.c 13 Oct 2015 19:57:48 - @@ -51,15 +51,20 @@ static int d_forwline(int, int); static int d_backline(int, int); static int d_killbuffer_cmd(int, int); static int d_refreshbuffer(int, int); +static int d_sort(int, int); static void reaper(int); static struct buffer *refreshbuffer(struct buffer *); static int createlist(struct buffer *); static void redelete(struct buffer *); static char *findfname(struct line *, char *); +static void finddotlsal(struct buffer *); extern struct keymap_s helpmap, cXmap, metamap; -const char DDELCHAR = 'D'; +const char DDELCHAR = 'D'; +const int LSALT = 4; /* 4 = -alt, 3 = -al) */ +charlsargs[5] = "-al"; /* see LSALT above */ +int lsarg_toggle = 0; /* 's' has implications for dot */ /* * Structure which holds a linked list of file names marked for @@ -134,7 +139,7 @@ static PF diredn[] = { d_backline, /* p */ d_killbuffer_cmd, /* q */ d_rename, /* r */ - rescan, /* s */ + d_sort, /* s */ rescan, /* t */ d_undel,/* u */ rescan, /* v */ @@ -212,6 +217,7 @@ dired_init(void) funmap_add(d_rename, "dired-do-rename"); funmap_add(d_backpage, "dired-scroll-down"); funmap_add(d_forwpage, "dired-scroll-up"); + funmap_add(d_sort, "dired-sort"); funmap_add(d_undel, "dired-unmark"); funmap_add(d_killbuffer_cmd, "quit-window"); maps_add((KEYMAP *), "dired"); @@ -750,7 +756,16 @@ refreshbuffer(struct buffer *bp) if (ddel) redelete(bp); - /* find dot line */ + /* If required, find suitable dot line if toggling sort order. */ + if (lsarg_toggle && (strlen(lsargs) == LSALT)) { + tmp_w_dotline = 2; /* 2nd line for -alt */ + lsarg_toggle = 0; + } else if (lsarg_toggle) { + finddotlsal(bp);/* or after ".." if -al */ + lsarg_toggle = 0; + curbp = bp; + return (bp); + } bp->b_dotp = bfirstlp(bp); if (tmp_w_dotline > bp->b_lines) tmp_w_dotline = bp->b_lines - 1; @@ -848,7 +863,6 @@ struct buffer * dired_(char *dname) { struct buffer *bp; - int i; size_t len; if ((dname = adjustname(dname, TRUE)) == NULL) { @@ -881,26 +895,11 @@ dired_(char *dname) bp = bfind(dname, TRUE); bp->b_flag |= BFREADONLY | BFIGNDIRTY; - if ((d_exec(2, bp, NULL, "ls", "-al", dname, NULL)) != TRUE) + if ((d_exec(2, bp, NULL, "ls", lsargs, dname, NULL)) != TRUE) return (NULL); - /* Find the line with ".." on it. */ - bp->b_dotp = bfirstlp(bp); - bp->b_dotline = 1; - for (i = 0; i < bp->b_lines; i++) { - bp->b_dotp = lforw(bp->b_dotp); - bp->b_dotline++; - if (d_warpdot(bp->b_dotp, >b_doto) == FALSE) - continue; - if (strcmp(ltext(bp->b_dotp) + bp->b_doto, "..") == 0) - break; - } + finddotlsal(bp); - /* We want dot on the entry right after "..", if possible. */ - if (++i < bp->b_lines - 2) { - bp->b_dotp = lforw(bp->b_dotp); - bp->b_dotline++; - } d_warpdot(bp->b_dotp, >b_doto); (void)strlcpy(bp->b_fname, dname, sizeof(bp->b_fname)); @@ -1035,4 +1034,46 @@ findfname(struct line *lp, char *fn) return NULL; fn = >l_text[start]; return fn; +} + +static int +d_sort(int f, int n) +{ + struct buffer *bp; + + if (strlen(lsargs) == LSALT) + (void)snprintf(lsargs, sizeof(lsargs), "-al"); + else + (void)snprintf(lsargs, sizeof(lsargs), "-alt"); + + lsarg_toggle = 1; + + if ((bp = refreshbuffer(curbp)) == NULL) + return (FALSE); + return (showbuffer(bp, curwp, WFFULL | WFMODE)); +} + +static void +finddotlsal(struct buffer *bp) +{ + int i; + + bp->b_dotp = bfirstlp(bp); + bp->b_dotline = 1; + for (i = 0; i < bp->b_lines; i++) { + bp->b_dotp = lforw(bp->b_dotp); + bp->b_dotline++; + if (d_warpdot(bp->b_dotp, >b_doto) == FALSE) + continue; +
mg(1) make dired-flag-file-deletion file more accurate
Instead of just seeing if a line in a dired buffer is longer than 0 before marking it for deletion, check if a filename has the potential to be extracted from a line. ok? -lum Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.78 diff -u -p -u -p -r1.78 dired.c --- dired.c 12 Oct 2015 19:08:39 - 1.78 +++ dired.c 12 Oct 2015 19:34:50 - @@ -286,7 +286,7 @@ d_del(int f, int n) if (n < 0) return (FALSE); while (n--) { - if (llength(curwp->w_dotp) > 0) { + if (d_warpdot(curwp->w_dotp, >w_doto) == TRUE) { lputc(curwp->w_dotp, 0, DDELCHAR); curbp->b_flag |= BFDIREDDEL; }
mg(1) Change onlywind() params
Calling onlywind() in this way should use FFRAND and 1 as the repective parameters. ok? -lum Index: buffer.c === RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.99 diff -u -p -u -p -r1.99 buffer.c --- buffer.c26 Sep 2015 21:51:58 - 1.99 +++ buffer.c9 Oct 2015 09:39:30 - @@ -408,7 +408,7 @@ listbuf_goto_buffer_helper(int f, int n, curwp = wp; if (only) - ret = (onlywind(f, n)); + ret = (onlywind(FFRAND, 1)); else ret = TRUE; Index: theo.c === RCS file: /cvs/src/usr.bin/mg/theo.c,v retrieving revision 1.146 diff -u -p -u -p -r1.146 theo.c --- theo.c 19 Mar 2015 21:48:05 - 1.146 +++ theo.c 9 Oct 2015 09:39:30 - @@ -78,7 +78,7 @@ theo(int f, int n) curbp = bp; curwp = wp; - onlywind(f, n); + onlywind(FFRAND, 1); return (TRUE); }
mg(1) onlywind() line number anomaly
If you open mg with only the *scratch* buffer loaded (no file names given on command line), and press enter 5 times, take a note of the line number in the status bar then open theo mode (M-x theo). Then move back to the *scratch* buffer via switch-to-buffer (C-x b). You'll notice the line number of the *scratch* buffer is now 1, though the cursor is on line 5. theo mode is initally opened splitting the screen in two, then onlywind() is called. The bug is in onlywind(). This diff fixes this behavior. ok? -lum Index: window.c === RCS file: /cvs/src/usr.bin/mg/window.c,v retrieving revision 1.33 diff -u -p -u -p -r1.33 window.c --- window.c25 Mar 2015 20:53:31 - 1.33 +++ window.c8 Oct 2015 19:49:34 - @@ -167,6 +167,8 @@ onlywind(int f, int n) wp->w_bufp->b_doto = wp->w_doto; wp->w_bufp->b_markp = wp->w_markp; wp->w_bufp->b_marko = wp->w_marko; + wp->w_bufp->b_dotline = wp->w_dotline; + wp->w_bufp->b_markline = wp->w_markline; } free(wp); } @@ -178,6 +180,8 @@ onlywind(int f, int n) wp->w_bufp->b_doto = wp->w_doto; wp->w_bufp->b_markp = wp->w_markp; wp->w_bufp->b_marko = wp->w_marko; + wp->w_bufp->b_dotline = wp->w_dotline; + wp->w_bufp->b_markline = wp->w_markline; } free(wp); }
mg(1) honour C-u 0
Calling an mg command with zero iterations (C-u 0) seems non-sensical but what should happen if you did? Currently some commands honour the 0 [ie. do nothing], others do not, they partially complete or complete as if 1 had been passed. For example try and insert 0 characters via: C-u 0 a The function that inserts characters has an 'if' statement that handles 0 being passed and returns before any characters are inserted. Now try to move to the beginning of a line: C-u 0 C-a The case for zero iterations isn't handled and the cursor goes to the beginning of the line. Now try tranposing 0 paragraphs: C-u 0 M-x tranpose-paragraphs The cursor moves to the end of the current paragraph and no transposing is completed. This diff makes functions that honour multiple* iterations but currently do not honour zero iterations, honour 0 iterations. Comments/oks? -lum * Functions that do not honour multiple (or non-single) iterations are not included, e.g: M-<. Also the tranpose-chars (C-t) function doesn't honour multiple iterations, but probably should so it has been included in this diff. Index: basic.c === RCS file: /cvs/src/usr.bin/mg/basic.c,v retrieving revision 1.46 diff -u -p -u -p -r1.46 basic.c --- basic.c 26 Sep 2015 21:51:58 - 1.46 +++ basic.c 7 Oct 2015 14:19:24 - @@ -28,6 +28,9 @@ int gotobol(int f, int n) { + if (n == 0) + return (TRUE); + curwp->w_doto = 0; return (TRUE); } @@ -72,6 +75,9 @@ backchar(int f, int n) int gotoeol(int f, int n) { + if (n == 0) + return (TRUE); + curwp->w_doto = llength(curwp->w_dotp); return (TRUE); } Index: paragraph.c === RCS file: /cvs/src/usr.bin/mg/paragraph.c,v retrieving revision 1.40 diff -u -p -u -p -r1.40 paragraph.c --- paragraph.c 26 Sep 2015 15:03:15 - 1.40 +++ paragraph.c 7 Oct 2015 14:19:25 - @@ -142,6 +142,9 @@ fillpara(int f, int n) struct line *eopline; /* pointer to line just past EOP */ char wbuf[MAXWORD]; /* buffer for current word */ + if (n == 0) + return (TRUE); + undo_boundary_enable(FFRAND, 0); /* record the pointer to the line just past the EOP */ @@ -267,6 +270,9 @@ killpara(int f, int n) { int lineno, status; + if (n == 0) + return (TRUE); + if (findpara() == FALSE) return (TRUE); @@ -298,6 +304,9 @@ markpara(int f, int n) { int i = 0; + if (n == 0) + return (TRUE); + clearmark(FFARG, 0); if (findpara() == FALSE) @@ -325,6 +334,9 @@ transposepara(int f, int n) { int i = 0, status; charflg; + + if (n == 0) + return (TRUE); /* find a paragraph, set mark, then goto the end */ gotobop(FFRAND, 1); Index: util.c === RCS file: /cvs/src/usr.bin/mg/util.c,v retrieving revision 1.36 diff -u -p -u -p -r1.36 util.c --- util.c 29 Sep 2015 03:19:24 - 1.36 +++ util.c 7 Oct 2015 14:19:25 - @@ -117,6 +117,9 @@ twiddle(int f, int n) struct line *dotp; int doto, cr; + if (n == 0) + return (TRUE); + dotp = curwp->w_dotp; doto = curwp->w_doto;
mg(1) keep 'D' marked files across dired refreshes
Hi, Currently, in mg dired mode, if you mark a file as deleted, if the dired buffer is refreshed (using 'dired-revert' for example) the marking of files is lost. This diff fixes that by saving the marked files before they are lost, then remarking them once the buffer is refreshed. Comments/oks? -lum Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.150 diff -u -p -u -p -r1.150 def.h --- def.h 29 Sep 2015 02:07:49 - 1.150 +++ def.h 6 Oct 2015 20:08:30 - @@ -288,7 +288,8 @@ struct buffer { #define BFOVERWRITE 0x08 /* overwrite mode*/ #define BFREADONLY 0x10 /* read only mode*/ #define BFDIRTY 0x20 /* Buffer was modified elsewhere */ -#define BFIGNDIRTY 0x40 /* Ignore modifications */ +#define BFIGNDIRTY 0x40 /* Ignore modifications */ +#define BFDIREDDEL 0x80 /* Dired has a deleted 'D' file */ /* * This structure holds information about recent actions for the Undo command. */ Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.77 diff -u -p -u -p -r1.77 dired.c --- dired.c 28 Sep 2015 11:56:17 - 1.77 +++ dired.c 6 Oct 2015 20:08:30 - @@ -53,9 +53,24 @@ static intd_killbuffer_cmd(int, int); static int d_refreshbuffer(int, int); static void reaper(int); static struct buffer *refreshbuffer(struct buffer *); +static void createlist(struct buffer *); +static void redelete(struct buffer *); +static char *findfname(struct line *, char *); extern struct keymap_s helpmap, cXmap, metamap; +const char DDELCHAR = 'D'; + +/* + * Structure which holds a linked list of file names marked for + * deletion. Used to maintain dired buffer 'state' between refreshes. + */ +struct delentry { + SLIST_ENTRY(delentry) entry; + char *fn; +}; +SLIST_HEAD(slisthead, delentry) delhead = SLIST_HEAD_INITIALIZER(delhead); + static PF dirednul[] = { setmark,/* ^@ */ gotobol,/* ^A */ @@ -271,8 +286,10 @@ d_del(int f, int n) if (n < 0) return (FALSE); while (n--) { - if (llength(curwp->w_dotp) > 0) - lputc(curwp->w_dotp, 0, 'D'); + if (llength(curwp->w_dotp) > 0) { + lputc(curwp->w_dotp, 0, DDELCHAR); + curbp->b_flag |= BFDIREDDEL; + } if (lforw(curwp->w_dotp) != curbp->b_headp) { curwp->w_dotp = lforw(curwp->w_dotp); curwp->w_dotline++; @@ -412,6 +429,8 @@ d_expunge(int f, int n) curwp->w_rflag |= WFFULL; } } + /* we have deleted all items successfully, remove del flag */ + bp->b_flag &= ~BFDIREDDEL curwp->w_dotline = tmp; d_warpdot(curwp->w_dotp, >w_doto); return (TRUE); @@ -692,26 +711,53 @@ d_refreshbuffer(int f, int n) return (showbuffer(bp, curwp, WFFULL | WFMODE)); } +/* + * Kill then re-open the requested dired buffer. + * If required, take a note of any files marked for deletion. Then once + * the buffer has been re-opened, remark the same files as deleted. + */ struct buffer * refreshbuffer(struct buffer *bp) { - char*tmp; + char*tmp_b_fname; + int i, tmp_w_dotline; - tmp = strdup(bp->b_fname); - if (tmp == NULL) { + /* remember directory path to open later */ + tmp_b_fname = strdup(bp->b_fname); + if (tmp_b_fname == NULL) { dobeep(); ewprintf("Out of memory"); return (NULL); } + tmp_w_dotline = curwp->w_dotline; + + /* create a list of files for deletion */ + if (bp->b_flag & BFDIREDDEL) + createlist(bp); killbuffer(bp); /* dired_() uses findbuffer() to create new buffer */ - if ((bp = dired_(tmp)) == NULL) { - free(tmp); + if ((bp = dired_(tmp_b_fname)) == NULL) { + free(tmp_b_fname); return (NULL); } - free(tmp); + free(tmp_b_fname); + + /* remark any previously deleted files with a 'D' */ + redelete(bp); + + /* find dot line */ + bp->b_dotp = bfirstlp(bp); + if (tmp_w_dotline > bp->b_lines) + tmp_w_dotline = bp->b_lines - 1; + for (i = 1; i < tmp_w_dotline; i++) + bp->b_dotp = lforw(bp->b_dotp); + + bp->b_dotline = i; + bp->b_doto = 0; + d_warpdot(bp->b_dotp, >b_doto); + curbp = bp; return (bp); @@ -865,4 +911,118 @@ dired_(char *dname) (void)fupdstat(bp); bp->b_nmodes = 1;
mg(1) filevisit and dired mode
hi, If you find-file (C-x C-f) and select a directory instead of a file, mg will eventually call dired but due to the current location of the call to dired in mg, find-file calls showbuffer() multiple times. Apart from being wastefull, doing this results in the cursor ending up on the wrong line of the dired buffer, it lands on line 1 instead of the line after "..". This diff checks to see if the requested path is a directory as soon as find-file is called, and if so calls dired. This removes the problems mention previously. Comments/ok? mark Index: file.c === RCS file: /cvs/src/usr.bin/mg/file.c,v retrieving revision 1.97 diff -u -p -u -p -r1.97 file.c --- file.c 25 Mar 2015 12:25:36 - 1.97 +++ file.c 25 Sep 2015 10:40:57 - @@ -45,10 +45,10 @@ fileinsert(int f, int n) } /* - * Select a file for editing. Look around to see if you can find the file - * in another buffer; if you can find it, just switch to the buffer. If - * you cannot find the file, create a new buffer, read in the text, and - * switch to the new buffer. + * Select a file for editing. If the file is a directory, invoke dired. + * Otherwise look around to see if you can find the file in another buffer; + * if you can find it, just switch to the buffer. If you cannot find the + * file, create a new buffer, read in the text, and switch to the new buffer. */ /* ARGSUSED */ int @@ -66,6 +66,12 @@ filevisit(int f, int n) return (ABORT); else if (bufp[0] == '\0') return (FALSE); + if (fisdir(fname) == TRUE) { + if ((bp = dired_(bufp)) == FALSE) + return (FALSE); + curbp = bp; + return (showbuffer(bp, curwp, WFFULL | WFMODE)); + } adjf = adjustname(fname, TRUE); if (adjf == NULL) return (FALSE);
mg(1) transpose-paragraph
While I am 'paragraph' mode, here is the useful 'transpose-paragraph' command. Comments/ok? mark Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.148 diff -u -p -u -p -r1.148 def.h --- def.h 24 Sep 2015 07:07:59 - 1.148 +++ def.h 24 Sep 2015 18:15:38 - @@ -588,6 +588,7 @@ int killpara(int, int); int fillword(int, int); int setfillcol(int, int); int markpara(int, int); +int transposepara(int, int); /* word.c X */ int backword(int, int); Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.50 diff -u -p -u -p -r1.50 funmap.c --- funmap.c24 Sep 2015 07:07:59 - 1.50 +++ funmap.c24 Sep 2015 18:15:38 - @@ -200,6 +200,7 @@ static struct funmap functnames[] = { {poptobuffer, "switch-to-buffer-other-window",}, {togglereadonly, "toggle-read-only" }, {twiddle, "transpose-chars",}, + {transposepara, "transpose-paragraph",}, {undo, "undo",}, {undo_add_boundary, "undo-boundary",}, {undo_boundary_enable, "undo-boundary-toggle",}, Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.92 diff -u -p -u -p -r1.92 mg.1 --- mg.124 Sep 2015 07:07:59 - 1.92 +++ mg.124 Sep 2015 18:15:38 - @@ -874,6 +874,10 @@ Toggle the read-only flag on the current Transpose the two characters in front of and under dot, then move forward one character. Treat newline characters the same as any other. +.It transpose-paragraph +Transpose adjacent paragraphs. +If multiple iterations are requested, the current paragraph will +be moved n paragraphs forward. .It undo Undo the most recent action. If invoked again without an intervening command, Index: paragraph.c === RCS file: /cvs/src/usr.bin/mg/paragraph.c,v retrieving revision 1.39 diff -u -p -u -p -r1.39 paragraph.c --- paragraph.c 24 Sep 2015 07:20:12 - 1.39 +++ paragraph.c 24 Sep 2015 18:15:38 - @@ -314,6 +314,50 @@ markpara(int f, int n) return (TRUE); } + +/* + * Transpose the current paragraph with the following paragraph. If invoked + * multiple times, transpose to the n'th paragraph. If invoked between + * paragraphs, move to the previous paragraph, then continue. + */ +/* ARGSUSED */ +int +transposepara(int f, int n) +{ + int i = 0, status; + charflg; + + /* find a paragraph, set mark, then goto the end */ + gotobop(FFRAND, 1); + curwp->w_markp = curwp->w_dotp; + curwp->w_marko = curwp->w_doto; + (void)gotoeop(FFRAND, 1); + + /* take a note of buffer flags - we may need them */ + flg = curbp->b_flag; + + /* clean out kill buffer then kill region */ + kdelete(); + if ((status = killregion(FFRAND, 1)) != TRUE) + return (status); + + /* +* Now step through n paragraphs. If we reach the end of buffer, +* stop and paste the killed region back, then display a message. +*/ + if (do_gotoeop(FFRAND, n, ) == FALSE) { + ewprintf("Cannot transpose paragraph, end of buffer reached."); + (void)gotobop(FFRAND, i); + (void)yank(FFRAND, 1); + curbp->b_flag = flg; + return (FALSE); + } + (void)yank(FFRAND, 1); + + return (TRUE); +} + + /* * Go down the buffer until we find a line with non-space characters. */
mg(1) dired-do-flagged-delete warpdot
In dired mode, I noticed that if the cursor is on a file marked for deletion when dired-do-flagged-delete (x) is called, the cursor is placed on the left hand side of the window. This diff makes d_expunge behave like other delete functions and calls d_warpdot to() place the cursor on the first character of a filename. ok? mark Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.74 diff -u -p -u -p -r1.74 dired.c --- dired.c 23 Sep 2015 05:03:03 - 1.74 +++ dired.c 24 Sep 2015 00:42:55 - @@ -413,6 +413,7 @@ d_expunge(int f, int n) } } curwp->w_dotline = tmp; + d_warpdot(curwp->w_dotp, >w_doto); return (TRUE); }
mg(1) - kill-paragraph tidy up
Hi, The kill-buffer command in mg doesn't behave quite as I would expect, if you invoke it multiple times via C-u #, then follow with M-_ (undo) or C-y (paste), only the last buffer killed (re)appears and not the multiple paragraphs that I think should. This diff changes that behaviour. Also, by fixing kill-paragraph I had worked out how to mark multiple paragraphs in one go, so the mark-paragraph command was straight forward to add in. This diff therefore is doing two things, fixing kill-paragraph and introducing the mark-paragraph command. I can split them out if required. Comments/ok? -lum Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.147 diff -u -p -u -p -r1.147 def.h --- def.h 3 Jun 2015 23:40:01 - 1.147 +++ def.h 17 Sep 2015 18:44:39 - @@ -587,6 +587,7 @@ int fillpara(int, int); int killpara(int, int); int fillword(int, int); int setfillcol(int, int); +int markpara(int, int); /* word.c X */ int backword(int, int); Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.49 diff -u -p -u -p -r1.49 funmap.c --- funmap.c19 Mar 2015 21:22:15 - 1.49 +++ funmap.c17 Sep 2015 18:44:39 - @@ -132,6 +132,7 @@ static struct funmap functnames[] = { {localunbind, "local-unset-key",}, {makebkfile, "make-backup-files",}, {makedir, "make-directory",}, + {markpara, "mark-paragraph",}, {markbuffer, "mark-whole-buffer",}, {do_meta, "meta-key-mode",},/* better name, anyone? */ {negative_argument, "negative-argument",}, Index: keymap.c === RCS file: /cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.55 diff -u -p -u -p -r1.55 keymap.c --- keymap.c19 Mar 2015 21:48:05 - 1.55 +++ keymap.c17 Sep 2015 18:44:39 - @@ -268,7 +268,9 @@ static PF metasqf[] = { capword,/* c */ delfword, /* d */ rescan, /* e */ - forwword/* f */ + forwword, /* f */ + rescan, /* g */ + markpara/* h */ }; static PF metal[] = { @@ -333,7 +335,7 @@ struct KEYMAPE (8) metamap = { '*', '>', metami, NULL }, { - '[', 'f', metasqf, (KEYMAP *) + '[', 'h', metasqf, (KEYMAP *) }, { 'l', '}', metal, NULL Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.91 diff -u -p -u -p -r1.91 mg.1 --- mg.19 Sep 2015 19:03:13 - 1.91 +++ mg.117 Sep 2015 18:44:39 - @@ -292,6 +292,8 @@ capitalize-word kill-word .It M-f forward-word +.It M-h +mark-paragraph .It M-l downcase-word .It M-m @@ -672,6 +674,8 @@ Unbind a key mapping in the local (topmo Toggle generation of backup files. .It make-directory Prompt the user for a path or directory name which is then created. +.It mark-paragraph +Mark the current paragraph. .It mark-whole-buffer Marks whole buffer as a region by putting dot at the beginning and mark at the end of buffer. Index: paragraph.c === RCS file: /cvs/src/usr.bin/mg/paragraph.c,v retrieving revision 1.36 diff -u -p -u -p -r1.36 paragraph.c --- paragraph.c 19 Mar 2015 21:22:15 - 1.36 +++ paragraph.c 17 Sep 2015 18:44:39 - @@ -20,6 +20,9 @@ static intfillcol = 70; #define MAXWORD 256 +static int findpara(void); +static int do_gotoeop(int, int, int *); + /* * Move to start of paragraph. * Move backwards by line, checking from the 1st character forwards for the @@ -70,7 +73,15 @@ gotobop(int f, int n) int gotoeop(int f, int n) { - int col, nospace; + int i; + + return(do_gotoeop(f, n, )); +} + +int +do_gotoeop(int f, int n, int *i) +{ + int col, nospace, j = 0; /* the other way... */ if (n < 0) @@ -78,6 +89,7 @@ gotoeop(int f, int n) /* for each one asked for */ while (n-- > 0) { + *i = ++j; nospace = 0; while (lforw(curwp->w_dotp) != curbp->b_headp) { col = 0; @@ -251,32 +263,82 @@ cleanup: int killpara(int f, int n) { - int status, end = FALSE;/* returned status of functions */ + int lineno, status; + + if (findpara() == FALSE) + return (TRUE); + + /* goto beginning of para */ + (void)gotobop(FFRAND, 1); - /* for each paragraph to delete */ - while (n--) { + /* take a
mg(1) startup file comments
ok to indicate a comment in an mg startup file with the '#' char? I can't see how this will break anybodys current startup files... -lum Index: extend.c === RCS file: /cvs/src/usr.bin/mg/extend.c,v retrieving revision 1.54 diff -u -p -u -p -r1.54 extend.c --- extend.c20 Mar 2014 07:47:29 - 1.54 +++ extend.c2 Apr 2014 18:35:21 - @@ -730,8 +730,9 @@ excline(char *line) f = 0; n = 1; funcp = skipwhite(line); - if (*funcp == '\0') - return (TRUE); /* No error on blank lines */ + /* No error on blank lines and skip comment lines. */ + if (*funcp == '\0' || *funcp == '#') + return (TRUE); line = parsetoken(funcp); if (*line != '\0') { *line++ = '\0'; Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.87 diff -u -p -u -p -r1.87 mg.1 --- mg.127 Mar 2014 07:30:25 - 1.87 +++ mg.12 Apr 2014 18:35:21 - @@ -1033,6 +1033,10 @@ set-default-mode fill set-fill-column 72 auto-execute *.c c-mode .Ed +.Pp +Comments can be added to the startup files by placing +.Dq # +as the first character of a line. .Sh FILES .Bl -tag -width /usr/share/doc/mg/tutorial -compact .It Pa ~/.mg
mg(1) find-file - missing directory
Currently, if you use find-file (C-x C-f) to find a file in a non- existant directory, mg (and emacs - coincidentally) suggest you create the directory manually with the make-directory command. This diff offers to create the missing directory by pressing 'y'. If mg cannot create the missing the directory for some reason, it behaves the same as before and opens a read-write buffer. Another option would be having mg try and create the directory on the fly (without having to press 'y') and then giving a message on its success or failure. comments/oks? -lum Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.140 diff -u -p -u -p -r1.140 def.h --- def.h 22 Mar 2014 11:05:37 - 1.140 +++ def.h 1 Apr 2014 06:18:55 - @@ -336,7 +336,8 @@ int changedir(int, int); int showcwdir(int, int); int getcwdir(char *, size_t); int makedir(int, int); -int do_makedir(void); +int do_makedir(char *); +int ask_makedir(void); /* dired.c */ struct buffer *dired_(char *); Index: dir.c === RCS file: /cvs/src/usr.bin/mg/dir.c,v retrieving revision 1.26 diff -u -p -u -p -r1.26 dir.c --- dir.c 31 Mar 2014 18:00:58 - 1.26 +++ dir.c 1 Apr 2014 06:18:55 - @@ -84,18 +84,15 @@ getcwdir(char *buf, size_t len) int makedir(int f, int n) { - return (do_makedir()); + return (ask_makedir()); } int -do_makedir(void) +ask_makedir(void) { - struct stat sb; - int finished, ishere; - mode_t dir_mode, mode, oumask; char bufc[NFILEN]; - char*slash, *path; + char*path; if (getbufcwd(bufc, sizeof(bufc)) != TRUE) return (ABORT); @@ -104,6 +101,17 @@ do_makedir(void) return (ABORT); else if (path[0] == '\0') return (FALSE); + + return (do_makedir(path)); +} + +int +do_makedir(char *path) +{ + struct stat sb; + int finished, ishere; + mode_t dir_mode, mode, oumask; + char*slash; if ((path = adjustname(path, TRUE)) == NULL) return (FALSE); Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.66 diff -u -p -u -p -r1.66 dired.c --- dired.c 20 Mar 2014 07:47:29 - 1.66 +++ dired.c 1 Apr 2014 06:18:55 - @@ -648,7 +648,7 @@ d_create_directory(int f, int n) int ret; struct buffer *bp; - ret = do_makedir(); + ret = ask_makedir(); if (ret != TRUE) return(ret); Index: file.c === RCS file: /cvs/src/usr.bin/mg/file.c,v retrieving revision 1.93 diff -u -p -u -p -r1.93 file.c --- file.c 31 Mar 2014 21:29:59 - 1.93 +++ file.c 1 Apr 2014 06:18:55 - @@ -231,10 +231,10 @@ readin(char *fname) (void)xdirname(dp, fname, sizeof(dp)); (void)strlcat(dp, /, sizeof(dp)); + /* Missing directory; keep buffer read-write, like emacs */ if (stat(dp, statbuf) == -1 errno == ENOENT) { - /* not read-only; like emacs */ - ewprintf(Use M-x make-directory RET RET to create the -directory and its parents); + if (eyorn(Missing directory, create) == TRUE) + (void)do_makedir(dp); } else if (access(dp, W_OK) == -1 errno == EACCES) { ewprintf(File not found and directory write-protected);
mg(1) dired-unmark-backward
Make 'dired-unmark-backward' behave the same as emacs. Any objections? -lum Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.63 diff -u -p -u -p -r1.63 dired.c --- dired.c 3 Jun 2013 05:10:59 - 1.63 +++ dired.c 19 Dec 2013 09:12:31 - @@ -305,11 +305,11 @@ d_undelbak(int f, int n) if (n 0) return (d_undel(f, -n)); while (n--) { - if (llength(curwp-w_dotp) 0) - lputc(curwp-w_dotp, 0, ' '); if (lback(curwp-w_dotp) != curbp-b_headp) curwp-w_dotp = lback(curwp-w_dotp); - } + if (llength(curwp-w_dotp) 0) + lputc(curwp-w_dotp, 0, ' '); + } curwp-w_rflag |= WFEDIT | WFMOVE; return (d_warpdot(curwp-w_dotp, curwp-w_doto)); }
mg(1) rename dired commands
This diff renames the dired-* command names to be in line with emacs. Any objections? mark Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.59 diff -u -p -r1.59 dired.c --- dired.c 30 May 2013 17:43:43 - 1.59 +++ dired.c 2 Jun 2013 08:07:53 - @@ -183,20 +183,20 @@ void dired_init(void) { funmap_add(dired, dired); - funmap_add(d_undelbak, dired-backup-unflag); + funmap_add(d_undelbak, dired-unmark-backward); funmap_add(d_create_directory, dired-create-directory); - funmap_add(d_copy, dired-copy-file); - funmap_add(d_expunge, dired-do-deletions); + funmap_add(d_copy, dired-do-copy); + funmap_add(d_expunge, dired-do-flagged-delete); funmap_add(d_findfile, dired-find-file); funmap_add(d_ffotherwindow, dired-find-file-other-window); - funmap_add(d_del, dired-flag-file-deleted); + funmap_add(d_del, dired-flag-file-deletion); funmap_add(d_forwline, dired-next-line); funmap_add(d_otherwindow, dired-other-window); funmap_add(d_backline, dired-previous-line); - funmap_add(d_rename, dired-rename-file); + funmap_add(d_rename, dired-do-rename); funmap_add(d_backpage, dired-scroll-down); funmap_add(d_forwpage, dired-scroll-up); - funmap_add(d_undel, dired-unflag); + funmap_add(d_undel, dired-unmark); maps_add((KEYMAP *)diredmap, dired); dobindkey(fundamental_map, dired, ^Xd); } Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.81 diff -u -p -r1.81 mg.1 --- mg.11 Jun 2013 17:33:49 - 1.81 +++ mg.12 Jun 2013 08:07:53 - @@ -936,9 +936,9 @@ dired-shell-command .It + dired-create-directory .It c -dired-copy-file +dired-do-copy .It d and C-d -dired-flag-file-deleted +dired-flag-file-deletion .It e, f and C-m dired-find-file .It n @@ -948,11 +948,11 @@ dired-find-file-other-window .It p dired-previous-line .It r -dired-rename-file +dired-do-rename .It u -dired-unflag +dired-unmark .It x -dired-do-deletions +dired-do-flagged-delete .It C-v dired-scroll-down .It M-v @@ -961,26 +961,25 @@ dired-scroll-up .Sh MG DIRED COMMANDS The following are a list of the commands specific to dired mode: .Bl -tag -width Ds -.It dired-backup-unflag -Remove the deletion flag from the file listed on the current line -of the dired buffer, then move up one line. -.It dired-copy-file -Copy the file listed on the current line of the dired buffer. .It dired-create-directory Create a directory. -.It dired-do-deletions +.It dired-do-copy +Copy the file listed on the current line of the dired buffer. +.It dired-do-flagged-delete Delete the files that have been flagged for deletion. +.It dired-do-rename +Rename the file listed on the current line of the dired buffer. .It dired-find-file Open the file on the current line of the dired buffer. If the cursor is on a directory it will be opened in dired mode. -.It dired-find-file-other-window -Open the file on the current line of the dired buffer in a -different window. -.It dired-flag-file-deleted +.It dired-flag-file-deletion Flag the file listed on the current line for deletion. This is indicated in the buffer by putting a D at the left margin. No files are actually deleted until the function dired-do-deletions is executed. +.It dired-find-file-other-window +Open the file on the current line of the dired buffer in a +different window. .It dired-next-line Move the cursor to the next line. .It dired-other-window @@ -988,14 +987,15 @@ This function works just like dired, exc dired buffer in another window. .It dired-previous-line Move the cursor to the previous line. -.It dired-rename-file -Rename the file listed on the current line of the dired buffer. .It dired-scroll-down Scroll down the dired buffer. .It dired-scroll-up Scroll up the dired buffer. -.It dired-unflag +.It dired-unmark Remove the deletion flag for the file on the current line. +.It dired-unmark-backward +Remove the deletion flag from the file listed on the current line +of the dired buffer, then move up one line. .El .Sh CONFIGURATION FILES There are two configuration files,
mg(1) 'g' dired refresh buffer
This diff uses 'g' to refresh the dired buffer. mark Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.62 diff -u -p -r1.62 dired.c --- dired.c 2 Jun 2013 10:09:21 - 1.62 +++ dired.c 2 Jun 2013 11:23:33 - @@ -45,6 +45,7 @@ static int d_backpage(int, int); static int d_forwline(int, int); static int d_backline(int, int); static int d_killbuffer_cmd(int, int); +static int d_refreshbuffer(int, int); static void reaper(int); static struct buffer *refreshbuffer(struct buffer *); @@ -103,7 +104,8 @@ static PF diredc[] = { d_copy, /* c */ d_del, /* d */ d_findfile, /* e */ - d_findfile /* f */ + d_findfile, /* f */ + d_refreshbuffer /* g */ }; static PF diredn[] = { @@ -166,7 +168,7 @@ static struct KEYMAPE (7 + NDIRED_XMAPS CCHR('Z'), '+', diredcz, (KEYMAP *) metamap }, { - 'c', 'f', diredc, NULL + 'c', 'g', diredc, NULL }, { 'n', 'x', diredn, NULL @@ -649,6 +651,17 @@ int d_killbuffer_cmd(int f, int n) { return(killbuffer_cmd(FFRAND, 0)); +} + +int +d_refreshbuffer(int f, int n) +{ + struct buffer *bp; + + if ((bp = refreshbuffer(curbp)) == NULL) + return (FALSE); + + return (showbuffer(bp, curwp, WFFULL | WFMODE)); } struct buffer * Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.83 diff -u -p -r1.83 mg.1 --- mg.12 Jun 2013 10:09:21 - 1.83 +++ mg.12 Jun 2013 11:23:33 - @@ -941,6 +941,8 @@ dired-do-copy dired-flag-file-deletion .It e, f and C-m dired-find-file +.It g +dired-revert .It n dired-next-line .It o @@ -989,6 +991,8 @@ This function works just like dired, exc dired buffer in another window. .It dired-previous-line Move the cursor to the previous line. +.It dired-revert +Refresh the dired buffer. .It dired-scroll-down Scroll down the dired buffer. .It dired-scroll-up
mg(1) 'q' for quit-window in dired mode
This diff adds the key binding 'q' and function 'quit-window' to mg's dired mode. Comments/oks? mark Index: buffer.c === RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.90 diff -u -p -r1.90 buffer.c --- buffer.c17 Feb 2013 10:30:26 - 1.90 +++ buffer.c1 Jun 2013 15:03:07 - @@ -124,10 +124,10 @@ poptobuffer(int f, int n) /* * Dispose of a buffer, by name. - * Ask for the name. Look it up (don't get too - * upset if it isn't there at all!). Clear the buffer (ask + * Ask for the name (unless called by dired mode). Look it up (don't + * get too upset if it isn't there at all!). Clear the buffer (ask * if the buffer has been changed). Then free the header - * line and the buffer header. Bound to C-X k. + * line and the buffer header. Bound to C-x k. */ /* ARGSUSED */ int @@ -136,7 +136,9 @@ killbuffer_cmd(int f, int n) struct buffer *bp; charbufn[NBUFN], *bufp; - if ((bufp = eread(Kill buffer: (default %s) , bufn, NBUFN, + if (f FFRAND) /* dired mode 'q' */ + bp = curbp; + else if ((bufp = eread(Kill buffer: (default %s) , bufn, NBUFN, EFNUL | EFNEW | EFBUF, curbp-b_bname)) == NULL) return (ABORT); else if (bufp[0] == '\0') Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.59 diff -u -p -r1.59 dired.c --- dired.c 30 May 2013 17:43:43 - 1.59 +++ dired.c 1 Jun 2013 15:03:07 - @@ -44,6 +44,7 @@ static int d_forwpage(int, int); static int d_backpage(int, int); static int d_forwline(int, int); static int d_backline(int, int); +static int d_killbuffer_cmd(int, int); static void reaper(int); static struct buffer *refreshbuffer(struct buffer *); @@ -109,7 +110,7 @@ static PF diredn[] = { d_forwline, /* n */ d_ffotherwindow,/* o */ d_backline, /* p */ - rescan, /* q */ + d_killbuffer_cmd, /* q */ d_rename, /* r */ rescan, /* s */ rescan, /* t */ @@ -197,6 +198,7 @@ dired_init(void) funmap_add(d_backpage, dired-scroll-down); funmap_add(d_forwpage, dired-scroll-up); funmap_add(d_undel, dired-unflag); + funmap_add(d_killbuffer_cmd, quit-window); maps_add((KEYMAP *)diredmap, dired); dobindkey(fundamental_map, dired, ^Xd); } @@ -640,6 +642,13 @@ d_create_directory(int f, int n) return (FALSE); return (showbuffer(bp, curwp, WFFULL | WFMODE)); +} + +/* ARGSUSED */ +int +d_killbuffer_cmd(int f, int n) +{ + return(killbuffer_cmd(FFRAND, 0)); } struct buffer * Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.80 diff -u -p -r1.80 mg.1 --- mg.11 Jun 2013 14:47:07 - 1.80 +++ mg.11 Jun 2013 15:03:07 - @@ -946,6 +946,8 @@ dired-next-line dired-find-file-other-window .It p dired-previous-line +.It q +dired-previous-line .It r dired-rename-file .It u @@ -995,6 +997,8 @@ Scroll down the dired buffer. Scroll up the dired buffer. .It dired-unflag Remove the deletion flag for the file on the current line. +.It quit-window +Closes the current dired buffer. .El .Sh CONFIGURATION FILES There are two configuration files,
[m...@showcomplex.com: mg(1) 'q' for quit-window in dired mode]
The man page has an error... it should read: .It q quit-window - Forwarded message from Mark Lumsden m...@showcomplex.com - Date: Sat, 1 Jun 2013 15:05:16 + From: Mark Lumsden m...@showcomplex.com To: tech@openbsd.org Subject: mg(1) 'q' for quit-window in dired mode User-Agent: Mutt/1.5.21 (2010-09-15) This diff adds the key binding 'q' and function 'quit-window' to mg's dired mode. Comments/oks? mark Index: buffer.c === RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.90 diff -u -p -r1.90 buffer.c --- buffer.c17 Feb 2013 10:30:26 - 1.90 +++ buffer.c1 Jun 2013 15:03:07 - @@ -124,10 +124,10 @@ poptobuffer(int f, int n) /* * Dispose of a buffer, by name. - * Ask for the name. Look it up (don't get too - * upset if it isn't there at all!). Clear the buffer (ask + * Ask for the name (unless called by dired mode). Look it up (don't + * get too upset if it isn't there at all!). Clear the buffer (ask * if the buffer has been changed). Then free the header - * line and the buffer header. Bound to C-X k. + * line and the buffer header. Bound to C-x k. */ /* ARGSUSED */ int @@ -136,7 +136,9 @@ killbuffer_cmd(int f, int n) struct buffer *bp; charbufn[NBUFN], *bufp; - if ((bufp = eread(Kill buffer: (default %s) , bufn, NBUFN, + if (f FFRAND) /* dired mode 'q' */ + bp = curbp; + else if ((bufp = eread(Kill buffer: (default %s) , bufn, NBUFN, EFNUL | EFNEW | EFBUF, curbp-b_bname)) == NULL) return (ABORT); else if (bufp[0] == '\0') Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.59 diff -u -p -r1.59 dired.c --- dired.c 30 May 2013 17:43:43 - 1.59 +++ dired.c 1 Jun 2013 15:03:07 - @@ -44,6 +44,7 @@ static int d_forwpage(int, int); static int d_backpage(int, int); static int d_forwline(int, int); static int d_backline(int, int); +static int d_killbuffer_cmd(int, int); static void reaper(int); static struct buffer *refreshbuffer(struct buffer *); @@ -109,7 +110,7 @@ static PF diredn[] = { d_forwline, /* n */ d_ffotherwindow,/* o */ d_backline, /* p */ - rescan, /* q */ + d_killbuffer_cmd, /* q */ d_rename, /* r */ rescan, /* s */ rescan, /* t */ @@ -197,6 +198,7 @@ dired_init(void) funmap_add(d_backpage, dired-scroll-down); funmap_add(d_forwpage, dired-scroll-up); funmap_add(d_undel, dired-unflag); + funmap_add(d_killbuffer_cmd, quit-window); maps_add((KEYMAP *)diredmap, dired); dobindkey(fundamental_map, dired, ^Xd); } @@ -640,6 +642,13 @@ d_create_directory(int f, int n) return (FALSE); return (showbuffer(bp, curwp, WFFULL | WFMODE)); +} + +/* ARGSUSED */ +int +d_killbuffer_cmd(int f, int n) +{ + return(killbuffer_cmd(FFRAND, 0)); } struct buffer * Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.80 diff -u -p -r1.80 mg.1 --- mg.11 Jun 2013 14:47:07 - 1.80 +++ mg.11 Jun 2013 15:03:07 - @@ -946,6 +946,8 @@ dired-next-line dired-find-file-other-window .It p dired-previous-line +.It q +dired-previous-line .It r dired-rename-file .It u @@ -995,6 +997,8 @@ Scroll down the dired buffer. Scroll up the dired buffer. .It dired-unflag Remove the deletion flag for the file on the current line. +.It quit-window +Closes the current dired buffer. .El .Sh CONFIGURATION FILES There are two configuration files, - End forwarded message -
mg(1) M-} forward para diff
A while back, I committed a diff that fixed scrolling backwards by paragraph in mg. I thought I would give it a while before writing the corresponding diff for going forwards, just to make sure there were no problems with the first diff. So here it is. Before you compile this diff, (and if you are using mg) put your cursor on the very first character of the first paragraph - an 'A', then do M-} your cursor stops on the 2nd line. In emacs it would stop on the 5th line. Currently mg stops moving forward when it finds a new line with a space on the first character, this diff checks the whole line before determinig if the line is a paragraph break or not. ok? mark Index: paragraph.c === RCS file: /cvs/src/usr.bin/mg/paragraph.c,v retrieving revision 1.24 diff -u -p -r1.24 paragraph.c --- paragraph.c 19 May 2013 10:27:11 - 1.24 +++ paragraph.c 1 Jun 2013 05:40:02 - @@ -63,37 +63,32 @@ gotobop(int f, int n) int gotoeop(int f, int n) { + int col; + int nospace = 0; + /* the other way... */ if (n 0) return (gotobop(f, -n)); /* for each one asked for */ while (n-- 0) { - /* Find the first word on/after the current line */ - curwp-w_doto = 0; - while (forwchar(FFRAND, 1) inword() == 0); + while (lforw(curwp-w_dotp) != curbp-b_headp) { + col = 0; + curwp-w_doto = 0; - curwp-w_doto = 0; - curwp-w_dotp = lforw(curwp-w_dotp); + while (col llength(curwp-w_dotp) + (isspace(lgetc(curwp-w_dotp, col + col++; - /* and scan forword until we hit a NLSP or ... */ - while (curwp-w_dotp != curbp-b_headp) { - if (llength(curwp-w_dotp) - lgetc(curwp-w_dotp, 0) != ' ' - lgetc(curwp-w_dotp, 0) != '.' - lgetc(curwp-w_dotp, 0) != '\t') { - curwp-w_dotp = lforw(curwp-w_dotp); - curwp-w_dotline++; + if (col = llength(curwp-w_dotp)) { + if (nospace) + break; } else - break; - } - if (curwp-w_dotp == curbp-b_headp) { - /* beyond end of buffer, cleanup time */ - curwp-w_dotp = lback(curwp-w_dotp); - curwp-w_doto = llength(curwp-w_dotp); - break; - } else + nospace = 1; + + curwp-w_dotp = lforw(curwp-w_dotp); curwp-w_dotline++; + } } /* force screen update */ curwp-w_rflag |= WFMOVE;
mg(1) visible/audible bell control
This diff adds the capability to toggle on and off the system bell within mg via the 'audible-bell' command. It also introduces the 'visible-bell' command: the modeline will flash instead. However, both can be used together, if so desired. Comments/oks? -lum Index: Makefile === RCS file: /cvs/src/usr.bin/mg/Makefile,v retrieving revision 1.27 diff -u -r1.27 Makefile --- Makefile18 Jun 2012 07:13:26 - 1.27 +++ Makefile30 May 2013 18:33:42 - @@ -15,7 +15,7 @@ # CFLAGS+=-Wall -DFKEYS -DREGEX -DXKEYS -SRCS= autoexec.c basic.c buffer.c cinfo.c dir.c display.c \ +SRCS= autoexec.c basic.c bell.c buffer.c cinfo.c dir.c display.c \ echo.c extend.c file.c fileio.c funmap.c help.c kbd.c keymap.c \ line.c macro.c main.c match.c modes.c paragraph.c random.c \ re_search.c region.c search.c spawn.c tty.c ttyio.c ttykbd.c \ Index: basic.c === RCS file: /cvs/src/usr.bin/mg/basic.c,v retrieving revision 1.39 diff -u -r1.39 basic.c --- basic.c 25 Mar 2013 11:41:44 - 1.39 +++ basic.c 30 May 2013 18:33:42 - @@ -43,8 +43,10 @@ while (n--) { if (curwp-w_doto == 0) { if ((lp = lback(curwp-w_dotp)) == curbp-b_headp) { - if (!(f FFRAND)) + if (!(f FFRAND)) { + dobeep(); ewprintf(Beginning of buffer); + } return (FALSE); } curwp-w_dotp = lp; @@ -85,8 +87,10 @@ curwp-w_dotp = lforw(curwp-w_dotp); if (curwp-w_dotp == curbp-b_headp) { curwp-w_dotp = lback(curwp-w_dotp); - if (!(f FFRAND)) + if (!(f FFRAND)) { + dobeep(); ewprintf(End of buffer); + } return (FALSE); } curwp-w_doto = 0; @@ -283,7 +287,7 @@ lp = curwp-w_linep; while (n--) if ((lp = lforw(lp)) == curbp-b_headp) { - ttbeep(); + dobeep(); ewprintf(End of buffer); return(TRUE); } @@ -332,7 +336,7 @@ lp = lback(lp); } if (lp == curwp-w_linep) { - ttbeep(); + dobeep(); ewprintf(Beginning of buffer); } curwp-w_linep = lp; Index: bell.c === RCS file: bell.c diff -N bell.c --- /dev/null 1 Jan 1970 00:00:00 - +++ bell.c 30 May 2013 18:33:42 - @@ -0,0 +1,57 @@ +/* $OpenBSD$ */ + +/* + * This file is in the public domain. + * + */ +/* + * Control how mg communicates with the user. + */ + +#include def.h + +void +bellinit(void) +{ + doaudiblebell = 1; + dovisiblebell = 0; + donebell = 0; +} + +void +dobeep(void) +{ + if (doaudiblebell) { + ttbeep(); + } + if (dovisiblebell) { + sgarbf = TRUE; + update(CNONE); + usleep(5); + } + donebell = 1; +} + +/* ARGSUSED */ +int +toggleaudiblebell(int f, int n) +{ + if (f FFARG) + doaudiblebell = n 0; + else + doaudiblebell = !doaudiblebell; + + return (TRUE); +} + +/* ARGSUSED */ +int +togglevisiblebell(int f, int n) +{ + if (f FFARG) + dovisiblebell = n 0; + else + dovisiblebell = !dovisiblebell; + + return (TRUE); +} Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.137 diff -u -r1.137 def.h --- def.h 30 May 2013 04:17:25 - 1.137 +++ def.h 30 May 2013 18:33:42 - @@ -424,7 +424,7 @@ intvtresize(int, int, int); void vtinit(void); void vttidy(void); -void update(void); +void update(int); intlinenotoggle(int, int); intcolnotoggle(int, int); @@ -681,6 +681,12 @@ int globalwdtoggle(int, int); int compile(int, int); +/* bell.c */ +voidbellinit(void); +int toggleaudiblebell(int, int); +int togglevisiblebell(int, int); +voiddobeep(void); + /* * Externals. */ @@ -704,6 +710,9 @@ extern int tthue; extern int defb_nmodes; extern int defb_flag; +extern int doaudiblebell; +extern int
mg(1) dired opening ~/
Currently dired mode doesn't use the adjustname() function early enough when passed ~. For example typing 'M-x dired', then: Dired: ~ Doesn't open your home directory. However, with this diff mg behaves like emacs. ok? mark Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.56 diff -u -p -r1.56 dired.c --- dired.c 29 May 2013 19:16:48 - 1.56 +++ dired.c 29 May 2013 19:38:33 - @@ -754,11 +754,6 @@ dired_(char *dname) int i; size_t len; - if ((access(dname, R_OK | X_OK)) == -1) { - if (errno == EACCES) - ewprintf(Permission denied); - return (NULL); - } if ((dname = adjustname(dname, FALSE)) == NULL) { ewprintf(Bad directory name); return (NULL); @@ -768,6 +763,11 @@ dired_(char *dname) if (dname[len - 1] != '/') { dname[len++] = '/'; dname[len] = '\0'; + } + if ((access(dname, R_OK | X_OK)) == -1) { + if (errno == EACCES) + ewprintf(Permission denied); + return (NULL); } if ((bp = findbuffer(dname)) == NULL) { ewprintf(Could not create buffer);
mg(1) - use more adjustname() in dired
The dired-copy-file and dired-rename-file commands do not use adjustname() for the new path. Hence 'M-x dired-copy-file': Dired: ~/filename will not work. This diff fixes that behaviour. ok? mark Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.58 diff -u -p -r1.58 dired.c --- dired.c 30 May 2013 04:27:18 - 1.58 +++ dired.c 30 May 2013 04:42:38 - @@ -398,10 +398,11 @@ d_expunge(int f, int n) int d_copy(int f, int n) { - charfrname[NFILEN], toname[NFILEN], sname[NFILEN], *bufp; - int ret; - size_t off; - struct buffer *bp; + char frname[NFILEN], toname[NFILEN], sname[NFILEN]; + char*topath, *bufp; + int ret; + size_t off; + struct buffer *bp; if (d_makename(curwp-w_dotp, frname, sizeof(frname)) != FALSE) { ewprintf(Not a file); @@ -419,7 +420,9 @@ d_copy(int f, int n) return (ABORT); else if (bufp[0] == '\0') return (FALSE); - ret = (copy(frname, toname) = 0) ? TRUE : FALSE; + + topath = adjustname(toname, TRUE); + ret = (copy(frname, topath) = 0) ? TRUE : FALSE; if (ret != TRUE) return (ret); if ((bp = refreshbuffer(curbp)) == NULL) @@ -431,7 +434,8 @@ d_copy(int f, int n) int d_rename(int f, int n) { - char frname[NFILEN], toname[NFILEN], *bufp; + char frname[NFILEN], toname[NFILEN]; + char*topath, *bufp; int ret; size_t off; struct buffer *bp; @@ -453,7 +457,9 @@ d_rename(int f, int n) return (ABORT); else if (bufp[0] == '\0') return (FALSE); - ret = (rename(frname, toname) = 0) ? TRUE : FALSE; + + topath = adjustname(toname, TRUE); + ret = (rename(frname, topath) = 0) ? TRUE : FALSE; if (ret != TRUE) return (ret); if ((bp = refreshbuffer(curbp)) == NULL)
mg(1) dired warpdot
The mg dired commands: dired-flag-file-deleted dired-backup-unflag dired-unflag behave more like emacs when the cursor stays on the first character of the file name. ok? mark Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.54 diff -u -p -r1.54 dired.c --- dired.c 28 May 2013 18:35:10 - 1.54 +++ dired.c 28 May 2013 19:09:15 - @@ -275,8 +275,7 @@ d_del(int f, int n) curwp-w_dotp = lforw(curwp-w_dotp); } curwp-w_rflag |= WFEDIT | WFMOVE; - curwp-w_doto = 0; - return (TRUE); + return (d_warpdot(curwp-w_dotp, curwp-w_doto)); } /* ARGSUSED */ @@ -292,8 +291,7 @@ d_undel(int f, int n) curwp-w_dotp = lforw(curwp-w_dotp); } curwp-w_rflag |= WFEDIT | WFMOVE; - curwp-w_doto = 0; - return (TRUE); + return (d_warpdot(curwp-w_dotp, curwp-w_doto)); } /* ARGSUSED */ @@ -308,9 +306,8 @@ d_undelbak(int f, int n) if (lback(curwp-w_dotp) != curbp-b_headp) curwp-w_dotp = lback(curwp-w_dotp); } - curwp-w_doto = 0; curwp-w_rflag |= WFEDIT | WFMOVE; - return (TRUE); + return (d_warpdot(curwp-w_dotp, curwp-w_doto)); } /* ARGSUSED */
mg(1) dired buffer refresh
In mg dired mode, if you execute these commands: dired-copy-file dired-rename-file dired-create-directory The dired buffer is not refreshed with the updated action. This diff fixes that. Comments/oks? -lum Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.52 diff -u -p -r1.52 dired.c --- dired.c 3 Nov 2012 15:36:03 - 1.52 +++ dired.c 27 May 2013 13:35:09 - @@ -44,6 +44,7 @@ static int d_backpage(int, int); static int d_forwline(int, int); static int d_backline(int, int); static void reaper(int); +static struct buffer *refreshbuffer(struct buffer *); extern struct keymap_s helpmap, cXmap, metamap; @@ -422,7 +423,8 @@ d_copy(int f, int n) ret = (copy(frname, toname) = 0) ? TRUE : FALSE; if (ret != TRUE) return (ret); - bp = dired_(curbp-b_fname); + if ((bp = refreshbuffer(curbp)) == NULL) + return (FALSE); return (showbuffer(bp, curwp, WFFULL | WFMODE)); } @@ -455,7 +457,8 @@ d_rename(int f, int n) ret = (rename(frname, toname) = 0) ? TRUE : FALSE; if (ret != TRUE) return (ret); - bp = dired_(curbp-b_fname); + if ((bp = refreshbuffer(curbp)) == NULL) + return (FALSE); return (showbuffer(bp, curwp, WFFULL | WFMODE)); } @@ -638,8 +641,28 @@ d_create_directory(int f, int n) tocreate); return (FALSE); } - bp = dired_(curbp-b_fname); + if ((bp = refreshbuffer(curbp)) == NULL) + return (FALSE); return (showbuffer(bp, curwp, WFFULL | WFMODE)); +} + +struct buffer * +refreshbuffer(struct buffer *bp) +{ + char*tmp; + + tmp = strdup(bp-b_fname); + killbuffer(bp); + + /* dired_() uses findbuffer() to create new buffer */ + if ((bp = dired_(tmp)) == NULL) { + free(tmp); + return (NULL); + } + free(tmp); + curbp = bp; + + return (bp); } static int
mg(1) dired buffer refresh
In mg dired mode, if you execute these commands: dired-copy-file dired-rename-file dired-create-directory The dired buffer is not refreshed with the updated action. This diff fixes that. Comments/oks? -lum Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.52 diff -u -p -r1.52 dired.c --- dired.c 3 Nov 2012 15:36:03 - 1.52 +++ dired.c 27 May 2013 13:35:09 - @@ -44,6 +44,7 @@ static int d_backpage(int, int); static int d_forwline(int, int); static int d_backline(int, int); static void reaper(int); +static struct buffer *refreshbuffer(struct buffer *); extern struct keymap_s helpmap, cXmap, metamap; @@ -422,7 +423,8 @@ d_copy(int f, int n) ret = (copy(frname, toname) = 0) ? TRUE : FALSE; if (ret != TRUE) return (ret); - bp = dired_(curbp-b_fname); + if ((bp = refreshbuffer(curbp)) == NULL) + return (FALSE); return (showbuffer(bp, curwp, WFFULL | WFMODE)); } @@ -455,7 +457,8 @@ d_rename(int f, int n) ret = (rename(frname, toname) = 0) ? TRUE : FALSE; if (ret != TRUE) return (ret); - bp = dired_(curbp-b_fname); + if ((bp = refreshbuffer(curbp)) == NULL) + return (FALSE); return (showbuffer(bp, curwp, WFFULL | WFMODE)); } @@ -638,8 +641,28 @@ d_create_directory(int f, int n) tocreate); return (FALSE); } - bp = dired_(curbp-b_fname); + if ((bp = refreshbuffer(curbp)) == NULL) + return (FALSE); return (showbuffer(bp, curwp, WFFULL | WFMODE)); +} + +struct buffer * +refreshbuffer(struct buffer *bp) +{ + char*tmp; + + tmp = strdup(bp-b_fname); + killbuffer(bp); + + /* dired_() uses findbuffer() to create new buffer */ + if ((bp = dired_(tmp)) == NULL) { + free(tmp); + return (NULL); + } + free(tmp); + curbp = bp; + + return (bp); } static int
mg(1) dired-create-directory
dired-create-directory is missing from the function maps. ok? -lum Index: dired.c === RCS file: /cvs/src/usr.bin/mg/dired.c,v retrieving revision 1.52 diff -u -p -r1.52 dired.c --- dired.c 3 Nov 2012 15:36:03 - 1.52 +++ dired.c 27 May 2013 13:48:01 - @@ -182,6 +182,7 @@ dired_init(void) { funmap_add(dired, dired); funmap_add(d_undelbak, dired-backup-unflag); + funmap_add(d_create_directory, dired-create-directory); funmap_add(d_copy, dired-copy-file); funmap_add(d_expunge, dired-do-deletions); funmap_add(d_findfile, dired-find-file);
mg.1 dired commands
I realised the dired commands are not in the mg man page. ok? -lum Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.76 diff -u -p -r1.76 mg.1 --- mg.122 May 2013 19:23:45 - 1.76 +++ mg.127 May 2013 19:10:45 - @@ -919,6 +919,43 @@ Unlike emacs, the kill buffer consists only of the most recent kill. It is not a ring. +.Sh MG DIRED COMMANDS +Following are a list of the commands specific to dired mode: +.It dired-backup-unflag +This function removes the deletion flag from the file listed on +the current line of the dired buffer, then moves up one line. +.It dired-create-directory +Creates a directory. +.It dired-copy-file +Copy the file listed on the current line of the dired buffer. +.It dired-do-deletions +Deletes the files that have been flagged for deletion. +.It dired-find-file +Opens the file in the current line of the dired buffer. +If the cursor is on a directory it will be opened in dired mode. +.It dired-find-file-other-window +Opens the file on the current line of the dired buffer in a +different window. +.It dired-flag-file-deleted +Flag the file listed on the current line for deletion. +This is indicated in the buffer by putting a D at the left margin. +No files are actually deleted until the function dired-do-deletions +is executed. +.It dired-next-line +Moves the cursor to the next line. +.It dired-other-window +This function works just like dired, except that it puts the +dired buffer in the other window. +.It dired-previous-line +Move the cursor to the previous line. +.It dired-rename-file +Renames the file listed on the current line of the dired buffer. +.It dired-scroll-down +Scroll down the dired buffer. +.It dired-scroll-up +Scroll up the dired buffer. +.It dired-unflag +Remove the deletion flag for the file on the current line. .El .Sh CONFIGURATION FILES There are two configuration files,
Re: mg(1): shell-command
To make the shell-command-on-region and this command behave like that requires another diff. mark On Wed, May 22, 2013 at 09:32:45AM +0200, Jasper Lievisse Adriaanse wrote: On Tue, May 21, 2013 at 07:54:31PM +, Mark Lumsden wrote: This diff modifies the shell-command-on-region function and gives us shell-command. It makes getting output from other commands into mg really easy. Comments/oks? -lum It seems Emacs doesn't split the window if the output from the command is only a single line (like 'date'), which is behaviour I quite like if you want to check something small. Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.135 diff -u -p -r1.135 def.h --- def.h 25 Mar 2013 11:41:44 - 1.135 +++ def.h 21 May 2013 19:46:38 - @@ -592,6 +592,7 @@ int region_get_data(struct region *, c voidregion_put_data(const char *, int); int markbuffer(int, int); int piperegion(int, int); +int shellcommand(int, int); int pipeio(const char * const, char * const[], char * const, int, struct buffer *); Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.45 diff -u -p -r1.45 funmap.c --- funmap.c27 Dec 2012 18:51:52 - 1.45 +++ funmap.c21 May 2013 19:46:38 - @@ -179,6 +179,7 @@ static struct funmap functnames[] = { {setfillcol, set-fill-column,}, {setmark, set-mark-command,}, {setprefix, set-prefix-string,}, + {shellcommand, shell-command,}, {piperegion, shell-command-on-region,}, {shrinkwind, shrink-window,}, #ifdef NOTAB Index: keymap.c === RCS file: /cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.50 diff -u -p -r1.50 keymap.c --- keymap.c7 Jun 2012 15:15:04 - 1.50 +++ keymap.c21 May 2013 19:46:38 - @@ -217,8 +217,9 @@ static PF metacV[] = { pagenext/* ^V */ }; -static PF metasp[] = { - justone /* space */ +static PF metaspex[] = { + justone,/* space */ + shellcommand/* ! */ }; static PF metapct[] = { @@ -317,7 +318,7 @@ struct KEYMAPE (8 + IMAPEXT) metamap = { CCHR('V'), CCHR('V'), metacV, NULL }, { - ' ', ' ', metasp, NULL + ' ', '!', metaspex, NULL }, { '%', '%', metapct, NULL Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.75 diff -u -p -r1.75 mg.1 --- mg.128 Dec 2012 16:12:50 - 1.75 +++ mg.121 May 2013 19:46:38 - @@ -268,6 +268,8 @@ suspend-emacs scroll-other-window .It M-SPC just-one-space +.It M-! +shell-command .It M-. find-tag .It M-* @@ -835,6 +837,8 @@ Used by auto-fill-mode. Sets the mark in the current window to the current dot location. .It set-prefix-string Sets the prefix string to be used by the 'prefix-region' command. +.It shell-command +Execute external command from mini-buffer. .It shell-command-on-region Provide the text in region to the shell command as input. .It shrink-window Index: region.c === RCS file: /cvs/src/usr.bin/mg/region.c,v retrieving revision 1.32 diff -u -p -r1.32 region.c --- region.c27 Dec 2012 18:49:59 - 1.32 +++ region.c21 May 2013 19:46:38 - @@ -28,6 +28,7 @@ staticint iomux(int, char * const, int, static int preadin(int, struct buffer *); static voidpwriteout(int, char **, int *); static int setsize(struct region *, RSIZE); +static int shellcmdoutput(char * const[], char * const, int); /* * Kill the region. Ask getregion to figure out the bounds of the region. @@ -406,9 +407,8 @@ int piperegion(int f, int n) { struct region region; - struct buffer *bp; - int len, ret; - char *cmd, cmdbuf[NFILEN], *shellp, *text; + int len; + char *cmd, cmdbuf[NFILEN], *text; char *argv[] = {sh, -c, (char *) NULL, (char *) NULL}; /* C-u M-| is not supported yet */ @@ -436,6 +436,51 @@ piperegion(int f, int n) return (FALSE); } + region_get_data(region, text, len); + + return shellcmdoutput(argv, text, len); +} + +/* + * Get command from mini-buffer and execute externally. + */ +/*ARGSUSED */ +int +shellcommand(int f, int n) +{ + + int len; + char *cmd
Re: mg(1): shell-command
I am glad to say, 3 of you are on your toes today. I sent the wrong diff, and to be honest I wasn't sure if any one would notice. Gold Stars to you all On Wed, May 22, 2013 at 09:07:56AM +, Florian Obser wrote: On Tue, May 21, 2013 at 07:54:31PM +, Mark Lumsden wrote: This diff modifies the shell-command-on-region function and gives us shell-command. It makes getting output from other commands into mg really easy. Comments/oks? -lum Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.135 diff -u -p -r1.135 def.h --- def.h 25 Mar 2013 11:41:44 - 1.135 +++ def.h 21 May 2013 19:46:38 - @@ -592,6 +592,7 @@ int region_get_data(struct region *, c voidregion_put_data(const char *, int); int markbuffer(int, int); int piperegion(int, int); +int shellcommand(int, int); int pipeio(const char * const, char * const[], char * const, int, struct buffer *); Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.45 diff -u -p -r1.45 funmap.c --- funmap.c27 Dec 2012 18:51:52 - 1.45 +++ funmap.c21 May 2013 19:46:38 - @@ -179,6 +179,7 @@ static struct funmap functnames[] = { {setfillcol, set-fill-column,}, {setmark, set-mark-command,}, {setprefix, set-prefix-string,}, + {shellcommand, shell-command,}, {piperegion, shell-command-on-region,}, {shrinkwind, shrink-window,}, #ifdef NOTAB Index: keymap.c === RCS file: /cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.50 diff -u -p -r1.50 keymap.c --- keymap.c7 Jun 2012 15:15:04 - 1.50 +++ keymap.c21 May 2013 19:46:38 - @@ -217,8 +217,9 @@ static PF metacV[] = { pagenext/* ^V */ }; -static PF metasp[] = { - justone /* space */ +static PF metaspex[] = { + justone,/* space */ + shellcommand/* ! */ }; static PF metapct[] = { @@ -317,7 +318,7 @@ struct KEYMAPE (8 + IMAPEXT) metamap = { CCHR('V'), CCHR('V'), metacV, NULL }, { - ' ', ' ', metasp, NULL + ' ', '!', metaspex, NULL }, { '%', '%', metapct, NULL Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.75 diff -u -p -r1.75 mg.1 --- mg.128 Dec 2012 16:12:50 - 1.75 +++ mg.121 May 2013 19:46:38 - @@ -268,6 +268,8 @@ suspend-emacs scroll-other-window .It M-SPC just-one-space +.It M-! +shell-command .It M-. find-tag .It M-* @@ -835,6 +837,8 @@ Used by auto-fill-mode. Sets the mark in the current window to the current dot location. .It set-prefix-string Sets the prefix string to be used by the 'prefix-region' command. +.It shell-command +Execute external command from mini-buffer. .It shell-command-on-region Provide the text in region to the shell command as input. .It shrink-window Index: region.c === RCS file: /cvs/src/usr.bin/mg/region.c,v retrieving revision 1.32 diff -u -p -r1.32 region.c --- region.c27 Dec 2012 18:49:59 - 1.32 +++ region.c21 May 2013 19:46:38 - @@ -28,6 +28,7 @@ staticint iomux(int, char * const, int, static int preadin(int, struct buffer *); static voidpwriteout(int, char **, int *); static int setsize(struct region *, RSIZE); +static int shellcmdoutput(char * const[], char * const, int); /* * Kill the region. Ask getregion to figure out the bounds of the region. @@ -406,9 +407,8 @@ int piperegion(int f, int n) { struct region region; - struct buffer *bp; - int len, ret; - char *cmd, cmdbuf[NFILEN], *shellp, *text; + int len; + char *cmd, cmdbuf[NFILEN], *text; char *argv[] = {sh, -c, (char *) NULL, (char *) NULL}; /* C-u M-| is not supported yet */ @@ -436,6 +436,51 @@ piperegion(int f, int n) return (FALSE); } + region_get_data(region, text, len); + + return shellcmdoutput(argv, text, len); +} + +/* + * Get command from mini-buffer and execute externally. + */ +/*ARGSUSED */ +int +shellcommand(int f, int n) +{ + + int len; + char *cmd, cmdbuf[NFILEN], *text; you don't need len and *text + char *argv[] = {sh, -c, (char *) NULL, (char *) NULL
mg(1): shell-command
This diff modifies the shell-command-on-region function and gives us shell-command. It makes getting output from other commands into mg really easy. Comments/oks? -lum Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.135 diff -u -p -r1.135 def.h --- def.h 25 Mar 2013 11:41:44 - 1.135 +++ def.h 21 May 2013 19:46:38 - @@ -592,6 +592,7 @@ int region_get_data(struct region *, c voidregion_put_data(const char *, int); int markbuffer(int, int); int piperegion(int, int); +int shellcommand(int, int); int pipeio(const char * const, char * const[], char * const, int, struct buffer *); Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.45 diff -u -p -r1.45 funmap.c --- funmap.c27 Dec 2012 18:51:52 - 1.45 +++ funmap.c21 May 2013 19:46:38 - @@ -179,6 +179,7 @@ static struct funmap functnames[] = { {setfillcol, set-fill-column,}, {setmark, set-mark-command,}, {setprefix, set-prefix-string,}, + {shellcommand, shell-command,}, {piperegion, shell-command-on-region,}, {shrinkwind, shrink-window,}, #ifdef NOTAB Index: keymap.c === RCS file: /cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.50 diff -u -p -r1.50 keymap.c --- keymap.c7 Jun 2012 15:15:04 - 1.50 +++ keymap.c21 May 2013 19:46:38 - @@ -217,8 +217,9 @@ static PF metacV[] = { pagenext/* ^V */ }; -static PF metasp[] = { - justone /* space */ +static PF metaspex[] = { + justone,/* space */ + shellcommand/* ! */ }; static PF metapct[] = { @@ -317,7 +318,7 @@ struct KEYMAPE (8 + IMAPEXT) metamap = { CCHR('V'), CCHR('V'), metacV, NULL }, { - ' ', ' ', metasp, NULL + ' ', '!', metaspex, NULL }, { '%', '%', metapct, NULL Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.75 diff -u -p -r1.75 mg.1 --- mg.128 Dec 2012 16:12:50 - 1.75 +++ mg.121 May 2013 19:46:38 - @@ -268,6 +268,8 @@ suspend-emacs scroll-other-window .It M-SPC just-one-space +.It M-! +shell-command .It M-. find-tag .It M-* @@ -835,6 +837,8 @@ Used by auto-fill-mode. Sets the mark in the current window to the current dot location. .It set-prefix-string Sets the prefix string to be used by the 'prefix-region' command. +.It shell-command +Execute external command from mini-buffer. .It shell-command-on-region Provide the text in region to the shell command as input. .It shrink-window Index: region.c === RCS file: /cvs/src/usr.bin/mg/region.c,v retrieving revision 1.32 diff -u -p -r1.32 region.c --- region.c27 Dec 2012 18:49:59 - 1.32 +++ region.c21 May 2013 19:46:38 - @@ -28,6 +28,7 @@ staticint iomux(int, char * const, int, static int preadin(int, struct buffer *); static voidpwriteout(int, char **, int *); static int setsize(struct region *, RSIZE); +static int shellcmdoutput(char * const[], char * const, int); /* * Kill the region. Ask getregion to figure out the bounds of the region. @@ -406,9 +407,8 @@ int piperegion(int f, int n) { struct region region; - struct buffer *bp; - int len, ret; - char *cmd, cmdbuf[NFILEN], *shellp, *text; + int len; + char *cmd, cmdbuf[NFILEN], *text; char *argv[] = {sh, -c, (char *) NULL, (char *) NULL}; /* C-u M-| is not supported yet */ @@ -436,6 +436,51 @@ piperegion(int f, int n) return (FALSE); } + region_get_data(region, text, len); + + return shellcmdoutput(argv, text, len); +} + +/* + * Get command from mini-buffer and execute externally. + */ +/*ARGSUSED */ +int +shellcommand(int f, int n) +{ + + int len; + char *cmd, cmdbuf[NFILEN], *text; + char *argv[] = {sh, -c, (char *) NULL, (char *) NULL}; + + if (n 1) + return (ABORT); + + if ((cmd = eread(Shell command: , cmdbuf, sizeof(cmdbuf), + EFNEW | EFCR)) == NULL || (cmd[0] == '\0')) + return (ABORT); + + argv[2] = cmd; + + len = strlen(cmd); + + if ((text = malloc(len + 1)) == NULL) { + ewprintf(Cannot allocate memory.); + return (FALSE); + } + + return shellcmdoutput(argv, NULL, 0); +} + + +int +shellcmdoutput(char* const argv[], char* const text,
adduser default blowfish rounds
Shouldn't the default rounds for blowfish in adduser.perl be the same as login.conf? ok? mark Index: adduser.perl === RCS file: /cvs/src/usr.sbin/adduser/adduser.perl,v retrieving revision 1.58 diff -u -p -u -p -r1.58 adduser.perl --- adduser.perl22 Sep 2011 10:59:23 - 1.58 +++ adduser.perl12 May 2013 20:09:47 - @@ -973,12 +973,12 @@ sub salt { $salt = ; } elsif ($encryptionmethod =~ /^blowfish/ ) { ($encryptionmethod, $salt) = split(/\,/, $encryptionmethod); - $salt = 7 unless $salt; # default rounds if unspecified + $salt = 6 unless $salt; # default rounds if unspecified } else { warn $encryptionmethod encryption method invalid\n if ($verbose 0); - warn Falling back to blowfish,7...\n if ($verbose 0); + warn Falling back to blowfish,6...\n if ($verbose 0); $encryptionmethod = blowfish; - $salt = 7; + $salt = 6; } warn Salt is: $salt\n if $verbose 1;
Re: adduser default blowfish rounds
On Mon, May 13, 2013 at 08:24:43PM +0100, Stuart Henderson wrote: On 2013/05/13 18:35, Mark Lumsden wrote: Shouldn't the default rounds for blowfish in adduser.perl be the same as login.conf? ok? mark Index: adduser.perl === RCS file: /cvs/src/usr.sbin/adduser/adduser.perl,v retrieving revision 1.58 diff -u -p -u -p -r1.58 adduser.perl --- adduser.perl22 Sep 2011 10:59:23 - 1.58 +++ adduser.perl12 May 2013 20:09:47 - @@ -973,12 +973,12 @@ sub salt { $salt = ; } elsif ($encryptionmethod =~ /^blowfish/ ) { ($encryptionmethod, $salt) = split(/\,/, $encryptionmethod); - $salt = 7 unless $salt; # default rounds if unspecified + $salt = 6 unless $salt; # default rounds if unspecified } else { warn $encryptionmethod encryption method invalid\n if ($verbose 0); - warn Falling back to blowfish,7...\n if ($verbose 0); + warn Falling back to blowfish,6...\n if ($verbose 0); $encryptionmethod = blowfish; - $salt = 7; + $salt = 6; } warn Salt is: $salt\n if $verbose 1; The default number of rounds in login.conf was set to 6 in 2001 when the 1.4GHz p3 xeon was a pretty decent cpu - this number needs to go up, not down. I agree. tedu suggest 9 for the number of user rounds and 11 for root back in 2010. Are these numbers reasonable on most archs?
mg(1) M-{} line number fix
Fix forward-paragraph and backward-paragraph's handling of line numbers. ok? -lum Index: paragraph.c === RCS file: /cvs/src/usr.bin/mg/paragraph.c,v retrieving revision 1.22 diff -u -p -r1.22 paragraph.c --- paragraph.c 29 Nov 2011 05:59:54 - 1.22 +++ paragraph.c 14 Feb 2013 20:35:18 - @@ -41,9 +41,10 @@ gotobop(int f, int n) if (llength(lback(curwp-w_dotp)) lgetc(curwp-w_dotp, 0) != ' ' lgetc(curwp-w_dotp, 0) != '.' - lgetc(curwp-w_dotp, 0) != '\t') + lgetc(curwp-w_dotp, 0) != '\t') { curwp-w_dotp = lback(curwp-w_dotp); - else { + curwp-w_dotline--; + } else { if (llength(lback(curwp-w_dotp)) lgetc(curwp-w_dotp, 0) == '.') { curwp-w_dotp = lforw(curwp-w_dotp); @@ -56,6 +57,7 @@ gotobop(int f, int n) lback(curwp-w_dotp); curwp-w_doto = llength(curwp-w_dotp); + curwp-w_dotline--; } } break; @@ -93,9 +95,10 @@ gotoeop(int f, int n) if (llength(curwp-w_dotp) lgetc(curwp-w_dotp, 0) != ' ' lgetc(curwp-w_dotp, 0) != '.' - lgetc(curwp-w_dotp, 0) != '\t') + lgetc(curwp-w_dotp, 0) != '\t') { curwp-w_dotp = lforw(curwp-w_dotp); - else + curwp-w_dotline++; + } else break; } if (curwp-w_dotp == curbp-b_headp) { @@ -103,7 +106,8 @@ gotoeop(int f, int n) curwp-w_dotp = lback(curwp-w_dotp); curwp-w_doto = llength(curwp-w_dotp); break; - } + } else + curwp-w_dotline++; } /* force screen update */ curwp-w_rflag |= WFMOVE;
Re: (Fwd) last(1) nit
Printing just the file name (as opposed to the full path) is how NetBSD and linux behave. FreeBSD has the same behaviour as OpenBSD. I'd follow the first 2. Any objections? -lum Might I suggest using basename()? --- last.c.orig 2009-10-27 23:59:39.0 + +++ last.c 2013-02-09 01:43:04.709416732 + @@ -36,6 +36,7 @@ #include ctype.h #include err.h #include fcntl.h +#include libgen.h #include paths.h #include signal.h #include stdio.h @@ -407,7 +408,7 @@ asctime(gmtime(total))+11); } ct = ctime(buf[0].ut_time); - printf(\nwtmp begins %10.10s %*.*s %4.4s\n, ct, timesize, timesize, + printf(\n%s begins %10.10s %*.*s %4.4s\n, basename(file), ct, timesize, timesize, ct + 11, ct + 20); }
lost user error message
There is an check when closing mg via C-x C-c, that if a file name is too long, the user should receive an error message Error: filename too long!, however, currently that message gets lost due to that check returning ABORT. This diff changes the return value to UERROR which allows the message to be shown. ok/comments? -lum Index: buffer.c === RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.80 diff -u -p -r1.80 buffer.c --- buffer.c30 Aug 2012 06:25:30 - 1.80 +++ buffer.c30 Aug 2012 20:59:10 - @@ -459,7 +459,7 @@ anycb(int f) bp-b_fname); if (ret 0 || ret = sizeof(pbuf)) { ewprintf(Error: filename too long!); - return (ABORT); + return (UERROR); } if ((f == TRUE || (save = eyorn(pbuf)) == TRUE) (save2 = buffsave(bp)) == TRUE) { Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.124 diff -u -p -r1.124 def.h --- def.h 14 Jun 2012 17:21:22 - 1.124 +++ def.h 30 Aug 2012 20:59:10 - @@ -36,6 +36,7 @@ typedef int (*PF)(int, int);/* generall #define FALSE 0 /* False, no, bad, etc. */ #define TRUE 1 /* True, yes, good, etc. */ #define ABORT 2 /* Death, ^G, abort, etc.*/ +#define UERROR 3 /* User Error. */ #define KCLEAR 2 /* clear echo area */ Index: main.c === RCS file: /cvs/src/usr.bin/mg/main.c,v retrieving revision 1.68 diff -u -p -r1.68 main.c --- main.c 30 Aug 2012 06:09:12 - 1.68 +++ main.c 30 Aug 2012 20:59:10 - @@ -224,7 +224,7 @@ quit(int f, int n) if ((s = anycb(FALSE)) == ABORT) return (ABORT); - if (s == FIOERR) + if (s == FIOERR || s == UERROR) return (FALSE); if (s == FALSE || eyesno(Modified buffers exist; really exit) == TRUE) {
mg(1) - closing buffer behaviour
If you C-x C-c out of emacs and there are unsaved buffers, emacs asks if you want to save them (mg behaves the same). If there is a write error (permissions or non-existant parent directory) emacs stops exiting. This allows the user to decide what to do with these buffers. In mg, the contents of these buffers are lost while mg continues to exit. This diff bring mg more into line with emacs. ok? -lum Index: buffer.c === RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.78 diff -u -p -r1.78 buffer.c --- buffer.c14 Mar 2012 13:56:35 - 1.78 +++ buffer.c28 Aug 2012 14:54:26 - @@ -449,7 +449,7 @@ int anycb(int f) { struct buffer *bp; - int s = FALSE, save = FALSE, ret; + int s = FALSE, save = FALSE, save2 = FALSE, ret; char pbuf[NFILEN + 11]; for (bp = bheadp; bp != NULL; bp = bp-b_bufp) { @@ -462,11 +462,14 @@ anycb(int f) return (ABORT); } if ((f == TRUE || (save = eyorn(pbuf)) == TRUE) - buffsave(bp) == TRUE) { + (save2 = buffsave(bp)) == TRUE) { bp-b_flag = ~BFCHG; upmodes(bp); - } else + } else { + if (save2 == FIOERR) + return (save2); s = TRUE; + } if (save == ABORT) return (save); save = TRUE; Index: file.c === RCS file: /cvs/src/usr.bin/mg/file.c,v retrieving revision 1.82 diff -u -p -r1.82 file.c --- file.c 28 Aug 2012 11:37:49 - 1.82 +++ file.c 28 Aug 2012 14:54:26 - @@ -662,8 +662,23 @@ makebkfile(int f, int n) int writeout(FILE ** ffp, struct buffer *bp, char *fn) { + struct stat statbuf; int s; + char*dp; + dp = dirname(fn); + + if (stat(fn, statbuf) == -1 errno == ENOENT) { + if (access(dp, W_OK) errno == EACCES) { + ewprintf(Directory %s%s write-protected, dp, + (dp[0] == '/' dp[1] == '\0') ? : /); + return (FIOERR); + } else if (errno == ENOENT) { +ewprintf(%s%s: no such directory, dp, +(dp[0] == '/' dp[1] == '\0') ? : /); + return (FIOERR); + } +} /* open writes message */ if ((s = ffwopen(ffp, fn, bp)) != FIOSUC) return (FALSE); Index: main.c === RCS file: /cvs/src/usr.bin/mg/main.c,v retrieving revision 1.67 diff -u -p -r1.67 main.c --- main.c 29 May 2012 06:08:48 - 1.67 +++ main.c 28 Aug 2012 14:54:26 - @@ -224,6 +224,8 @@ quit(int f, int n) if ((s = anycb(FALSE)) == ABORT) return (ABORT); + if (s == FIOERR) + return (FALSE); if (s == FALSE || eyesno(Modified buffers exist; really exit) == TRUE) { vttidy();
Re: tinyscheme + mg
Here is an updated diff for mg with tinyscheme integration. It's based on tedu's original diff with various tweaks and changes. For those worried about mg being too bloated, rest assured, it's still small and lean and a big part smaller than vi ;-) It's not fully possible to turn mg into your mail client, but I'd like to commit this diff and work on it futher in tree (not the mail-client thing, that would bloat mg and that's far from desired). Includes some fixes by lum@ and Sunil Nimmagadda too. Diff is also at http://crappydiffs.org/tinyschemg.diff I would appreciate some feedback on the inclusion of this diff in mg since I am unlikely to use tinyscheme myself but can see why others would like it added. Are there are strong feelings about it either way? -lum
Re: tinyscheme + mg
I'm all for adding support for scripting into mg, though I would be tempted to rip out all nonessential functionality first (ng? ;) and add it back via the scripting language. I would think the goal should be to make mg significantly *smaller* any such change Could you clarify what you mean by non-essential functionality? mark
Re: tinyscheme + mg
I'd be a lot happier voicing an opinion in support of something like this if I also saw diffs and interest in *using* them to extend functionality later or replace some things easier to do with scheme to make the code simpler - something kjell was alluding to. I think we can work towards that, but there's a bit of chicken and egg problem here. I'm not inclined to do a lot of work if the answer in two months is going to be oh, sorry, perl would have been cooler. The diff will only get larger from here. A promise of this is bigger and bloated now but will be really cool in the future isn't so good if the people putting it in see getting scheme integration in as the goal - otherwise, congrats, you've Integration is one of the goals. I can't predict what extensions you may want to write. I mean, mg already reads a .mg file. If we knew what people were going to put in their .mg files, we could just hard code it in the program and cut out the startup file bloat. That said, some concrete examples would help, both to make sure we're building something useful and to demonstrate that it is useful. Why do people still use emacs and not mg? For text editing not usenet browsing or whatever. +1 to somebody providing concrete examples.
mg - end-of-buffer diff
Currently, if you are at the start of a buffer that is longer than the window and press M-, you will move to the end of the buffer. There is a difference between mg and emacs' behaviour though. In emacs, your cursor will be placed at the bottom of the window (minus 3 lines) which means most of the window above is displaying buffer contents, while mg places the cursor in the middle of the window only allowing half the screen to display buffer contents. This diff makes mg behave the same as emacs. ok? -lum Index: basic.c === RCS file: /cvs/src/usr.bin/mg/basic.c,v retrieving revision 1.36 diff -u -p -r1.36 basic.c --- basic.c 8 Jun 2012 21:21:57 - 1.36 +++ basic.c 16 Jun 2012 03:03:54 - @@ -115,17 +115,30 @@ gotobob(int f, int n) } /* - * Go to the end of the buffer. - * Setting WFFULL is conservative, but - * almost always the case. + * Go to the end of the buffer. Leave dot 3 lines from the bottom of the + * window if buffer length is longer than window length; same as emacs. + * Setting WFFULL is conservative, but almost always the case. */ int gotoeob(int f, int n) { + struct line *lp; + (void) setmark(f, n); curwp-w_dotp = blastlp(curbp); curwp-w_doto = llength(curwp-w_dotp); curwp-w_dotline = curwp-w_bufp-b_lines; + + lp = curwp-w_dotp; + n = curwp-w_ntrows - 3; + + if (n curwp-w_bufp-b_lines n = 3) { + while (n--) + curwp-w_dotp = lback(curwp-w_dotp); + + curwp-w_linep = curwp-w_dotp; + curwp-w_dotp = lp; + } curwp-w_rflag |= WFFULL; return (TRUE); }
mg - another ~file bug
Currently, in mg, if you try to open a file that doesn't exist and has a name longer than LOGIN_NAME_MAX and also has a tilde at the front e.g. $ mg ~01234567890123456789012345678901 you will receive a msg: Login name too long Since the filename cannot be a user name (it is too long), mg should open up a new buffer with the file name as the buffer name. This diff makes mg behave like that which also mimics the behaviour of emacs. As you can see I have put all the relevant code in a function, the fix concerns the lines following: + if (ulen = sizeof(user)) { ok? -lum Index: fileio.c === RCS file: /cvs/src/usr.bin/mg/fileio.c,v retrieving revision 1.91 diff -u -p -r1.91 fileio.c --- fileio.c14 Jun 2012 17:21:22 - 1.91 +++ fileio.c14 Jun 2012 17:56:42 - @@ -24,6 +24,7 @@ static char *bkuplocation(const char *); static int bkupleavetmp(const char *); +char *expandtilde(const char *); static char *bkupdir; static int leavetmp = 0; /* 1 = leave any '~' files in tmp dir */ @@ -281,13 +282,9 @@ fbackupfile(const char *fn) char * adjustname(const char *fn, int slashslash) { - struct stat statbuf; static char fnb[MAXPATHLEN]; const char *cp, *ep = NULL; - char user[LOGIN_NAME_MAX], path[MAXPATHLEN]; - size_t ulen, plen; - - path[0] = '\0'; + char*path; if (slashslash == TRUE) { cp = fn + strlen(fn) - 1; @@ -302,50 +299,8 @@ adjustname(const char *fn, int slashslas ep = NULL; } } - - /* -* Next, expand file names beginning with '~', if appropriate: -* 1, if ./~fn exists, continue without expanding tilde. -* 2, otherwise, if username 'fn' exists, expand tilde with home -* directory path. -* 3, otherwise, continue and create new buffer called ~fn. -*/ - if (fn[0] == '~' stat(fn, statbuf) != 0) { - struct passwd *pw; - - cp = strchr(fn, '/'); - if (cp == NULL) - cp = fn + strlen(fn); /* point to the NUL byte */ - ulen = cp - fn[1]; - if (ulen = sizeof(user)) { - ewprintf(Login name too long); - return (NULL); - } - if (ulen == 0) /* ~/ or ~ */ - (void)strlcpy(user, getlogin(), sizeof(user)); - else { /* ~user/ or ~user */ - memcpy(user, fn[1], ulen); - user[ulen] = '\0'; - } - pw = getpwnam(user); - if (pw != NULL) { - plen = strlcpy(path, pw-pw_dir, sizeof(path)); - if (plen == 0 || path[plen - 1] != '/') { - if (strlcat(path, /, sizeof(path)) = - sizeof(path)) { - ewprintf(Path too long); - return (NULL); - } - } - fn = cp; - if (*fn == '/') - fn++; - } - } - if (strlcat(path, fn, sizeof(path)) = sizeof(path)) { - ewprintf(Path too long); + if ((path = expandtilde(fn)) == NULL) return (NULL); - } if (realpath(path, fnb) == NULL) (void)strlcpy(fnb, path, sizeof(fnb)); @@ -730,4 +685,64 @@ bkupleavetmp(const char *fn) return (TRUE); return (FALSE); +} + +/* + * Expand file names beginning with '~' if appropriate: + * 1, if ./~fn exists, continue without expanding tilde. + * 2, else, if username 'fn' exists, expand tilde with home directory path. + * 3, otherwise, continue and create new buffer called ~fn. + */ +char * +expandtilde(const char *fn) +{ + struct passwd *pw; + struct stat statbuf; + const char *cp; + char user[LOGIN_NAME_MAX], path[NFILEN], *ret; + size_t ulen, plen; + + path[0] = '\0'; + +if (fn[0] != '~' || stat(fn, statbuf) == 0) { + if ((ret = strndup(fn, NFILEN)) == NULL) + return (NULL); + return(ret); + } + cp = strchr(fn, '/'); + if (cp == NULL) + cp = fn + strlen(fn); /* point to the NUL byte */ + ulen = cp - fn[1]; + if (ulen = sizeof(user)) { + if ((ret = strndup(fn, NFILEN)) == NULL) + return (NULL); + return(ret); + } + if (ulen == 0) /* ~/ or ~ */ + (void)strlcpy(user, getlogin(), sizeof(user)); + else { /* ~user/ or ~user */ + memcpy(user,
mg - save backup files to homedir (diff v3)
If you use mg as the editor with mutt, any backup files mutt creates are kept in /tmp. However, with backup-to-home-directory enabled all backup files are moved to ~/.mg.d. Personally, I'd rather not move these backups but keep them in the /tmp dir. This modified diff allows backup files that are located in the /tmp directory to stay there, while allowing all other backups to go to the ~/.mg.d directory. Arguably, this could just be made the default behaviour (with backup-to-home-directory enabled), however I wrote the diff with an added an option so am sending the diff with it in. Also, since this option is not exactly the same as an emacs command I have chosen a non emacs command name: leave-tmpdir-backups Of course, by default nothing is changed in mg. Backups are still kept in the current directory. Comments/ok? -lum Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.123 diff -u -p -r1.123 def.h --- def.h 7 Jun 2012 15:15:04 - 1.123 +++ def.h 13 Jun 2012 12:33:06 - @@ -446,6 +446,8 @@ struct list *make_file_list(char *); int fisdir(const char *); int fchecktime(struct buffer *); int fupdstat(struct buffer *); +int backuptohomedir(int, int); +int toggleleavetmp(int, int); /* kbd.c X */ int do_meta(int, int); Index: fileio.c === RCS file: /cvs/src/usr.bin/mg/fileio.c,v retrieving revision 1.90 diff -u -p -r1.90 fileio.c --- fileio.c11 Jun 2012 18:30:03 - 1.90 +++ fileio.c13 Jun 2012 12:33:06 - @@ -22,6 +22,12 @@ #include kbd.h +static char *bkuplocation(const char *); +static int bkupleavetmp(const char *); + +static char *bkupdir; +static int leavetmp = 0; /* 1 = leave any '~' files in tmp dir */ + /* * Open a file for reading. */ @@ -203,23 +209,28 @@ fbackupfile(const char *fn) int from, to, serrno; ssize_t nread; char buf[BUFSIZ]; - char*nname, *tname; + char*nname, *tname, *bkpth; if (stat(fn, sb) == -1) { ewprintf(Can't stat %s : %s, fn, strerror(errno)); return (FALSE); } - if (asprintf(nname, %s~, fn) == -1) { + if ((bkpth = bkuplocation(fn)) == NULL) + return (FALSE); + + if (asprintf(nname, %s~, bkpth) == -1) { ewprintf(Can't allocate backup file name : %s, strerror(errno)); + free(bkpth); return (ABORT); } - - if (asprintf(tname, %s.XX, fn) == -1) { + if (asprintf(tname, %s.XX, bkpth) == -1) { ewprintf(Can't allocate temp file name : %s, strerror(errno)); + free(bkpth); free(nname); return (ABORT); } + free(bkpth); if ((from = open(fn, O_RDONLY)) == -1) { free(nname); @@ -610,4 +621,113 @@ fchecktime(struct buffer *bp) return (TRUE); +} + +/* + * Location of backup file. This function creates the correct path. + */ +static char * +bkuplocation(const char *fn) +{ + struct stat sb; + char *ret; + + if (bkupdir != NULL (stat(bkupdir, sb) == 0) + S_ISDIR(sb.st_mode) !bkupleavetmp(fn)) { + char fname[NFILEN]; + const char *c; + int i = 0, len; + + c = fn; + len = strlen(bkupdir); + + while (*c != '\0') { + /* Make sure we don't go over combined: + * strlen(bkupdir + '/' + fname + '\0') + */ + if (i = NFILEN - len - 1) + return (NULL); + if (*c == '/') { + fname[i] = '!'; + } else if (*c == '!') { + if (i = NFILEN - len - 2) + return (NULL); + fname[i++] = '!'; + fname[i] = '!'; + } else + fname[i] = *c; + i++; + c++; + } + fname[i] = '\0'; + if (asprintf(ret, %s/%s, bkupdir, fname) == -1) + return (NULL); + + } else if ((ret = strndup(fn, NFILEN)) == NULL) + return (NULL); + + return (ret); +} + +int +backuptohomedir(int f, int n) +{ + const char *c = ~/.mg.d; + char*p; + + if (bkupdir == NULL) { + p = adjustname(c, TRUE); + bkupdir = strndup(p, NFILEN); + if (bkupdir == NULL) + return(FALSE); + + if
Re: mg - save backup files to homedir (diff v2)
So perhaps it is better for mg to behave more like emacs when it comes to saving backup files in a single directory. Especially if a user has two files open with the same name and are working on them simultaneously. In this diff I've added the path to the backup file name. Like emacs, it changes any '/' to '!'. Here is a slightly modified diff; add NUL termination to backup path. Are there objections to this going in? -lum Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.123 diff -u -p -r1.123 def.h --- def.h 7 Jun 2012 15:15:04 - 1.123 +++ def.h 9 Jun 2012 20:22:10 - @@ -446,6 +446,7 @@ struct list *make_file_list(char *); int fisdir(const char *); int fchecktime(struct buffer *); int fupdstat(struct buffer *); +int backuptohomedir(int, int); /* kbd.c X */ int do_meta(int, int); Index: fileio.c === RCS file: /cvs/src/usr.bin/mg/fileio.c,v retrieving revision 1.89 diff -u -p -r1.89 fileio.c --- fileio.c25 May 2012 04:56:58 - 1.89 +++ fileio.c9 Jun 2012 20:22:10 - @@ -22,6 +22,10 @@ #include kbd.h +static char *bkuplocation(const char *); + +static char *bkupdir; + /* * Open a file for reading. */ @@ -189,6 +193,51 @@ ffgetline(FILE *ffp, char *buf, int nbuf } /* + * Location of backup file. This function creates the correct path. + */ +static char * +bkuplocation(const char *fn) +{ + struct stat sb; + char *ret; + + if (bkupdir != NULL (stat(bkupdir, sb) == 0) + S_ISDIR(sb.st_mode)) { + char fname[NFILEN]; + const char *c; + int i = 0, len; + + c = fn; + len = strlen(bkupdir); + + while (*c != '\0') { + /* Make sure we don't go over combined: +* strlen(bkupdir + '/' + fname + '\0') +*/ + if (i = NFILEN - len - 1) + return (NULL); + if (*c == '/') { + fname[i] = '!'; + } else if (*c == '!') { + if (i = NFILEN - len - 2) + return (NULL); + fname[i++] = '!'; + fname[i] = '!'; + } else + fname[i] = *c; + i++; + c++; + } + fname[i] = '\0'; + if (asprintf(ret, %s/%s, bkupdir, fname) == -1) + return (NULL); + } else if ((ret = strndup(fn, NFILEN)) == NULL) + return (NULL); + + return (ret); +} + +/* * Make a backup copy of fname. On Unix the backup has the same * name as the original file, with a ~ on the end; this seems to * be newest of the new-speak. The error handling is all in file.c. @@ -203,23 +252,29 @@ fbackupfile(const char *fn) int from, to, serrno; ssize_t nread; char buf[BUFSIZ]; - char*nname, *tname; + char*nname, *tname, *bkpth; if (stat(fn, sb) == -1) { ewprintf(Can't stat %s : %s, fn, strerror(errno)); return (FALSE); } - if (asprintf(nname, %s~, fn) == -1) { + if ((bkpth = bkuplocation(fn)) == NULL) + return (FALSE); + + if (asprintf(nname, %s~, bkpth) == -1) { ewprintf(Can't allocate temp file name : %s, strerror(errno)); + free(bkpth); return (ABORT); } - if (asprintf(tname, %s.XX, fn) == -1) { + if (asprintf(tname, %s.XX, bkpth) == -1) { ewprintf(Can't allocate temp file name : %s, strerror(errno)); + free(bkpth); free(nname); return (ABORT); } + free(bkpth); if ((from = open(fn, O_RDONLY)) == -1) { free(nname); @@ -610,4 +665,28 @@ fchecktime(struct buffer *bp) return (TRUE); +} + +int +backuptohomedir(int f, int n) +{ + const char *c = ~/.mg.d; + char*p; + + if (bkupdir == NULL) { + p = adjustname(c, TRUE); + bkupdir = strndup(p, NFILEN); + if (bkupdir == NULL) + return(FALSE); + + if (mkdir(bkupdir, 0700) == -1 errno != EEXIST) { + free(bkupdir); + bkupdir = NULL; + } + } else { + free(bkupdir); + bkupdir = NULL; + } + + return (TRUE); } Index: funmap.c
mg - Another corner-case scrolling fix
Bit difficult to explain this one. If you have a file open that is 3 or 4 times longer than the length of the viewable window and are at the bottom of the buffer then scroll up to the top using M-v, your cursor should remain at the bottom left of the window once you reach the top of the buffer. mg behaves like this since the last couple of scrolling diffs I've committed. However, and as an example, if you start with the window viewing the top of a buffer and press C-v twice, then C-p four times then M-v twice to scroll back to the top, you will find your cursor is NOT at the bottom left of the window. tut tut. This diff makes the cursor stay at the bottom left, like emacs. ok? -lum Index: basic.c === RCS file: /cvs/src/usr.bin/mg/basic.c,v retrieving revision 1.35 diff -u -p -r1.35 basic.c --- basic.c 8 Jun 2012 05:10:50 - 1.35 +++ basic.c 8 Jun 2012 15:09:22 - @@ -334,6 +334,8 @@ backpage(int f, int n) /* Move the dot the slow way, for line nos */ while (curwp-w_dotp != lp2) { +if (curwp-w_dotline = curwp-w_ntrows) +return (TRUE); curwp-w_dotp = lback(curwp-w_dotp); curwp-w_dotline--; }
Re: mg - corner-case backward scrolling
There is a corner case when the screen buffer is only 1 line long where the loop that looks for the current dot line goes through the whole buffer until it finds the correct line. This means the line number decrement is way over what it should be. This diff accounts for that corner case. ok? This version uses the existing function backline() that already moves the cursor and linep by one line. This keeps the backpage() function for paging backwards. -lum Index: basic.c === RCS file: /cvs/src/usr.bin/mg/basic.c,v retrieving revision 1.34 diff -u -p -r1.34 basic.c --- basic.c 1 Jun 2012 11:22:06 - 1.34 +++ basic.c 7 Jun 2012 15:25:34 - @@ -309,7 +309,7 @@ backpage(int f, int n) if (!(f FFARG)) { n = curwp-w_ntrows - 2;/* Default scroll. */ if (n = 0) /* Don't blow up if the */ - n = 1; /* window is tiny. */ + return(backline(f, 1)); /* window is tiny. */ } else if (n 0) return (forwpage(f | FFRAND, -n));
mg - save backup files to homedir (diff v2)
[note: I've modifed this diff from the first version with comments from eric@ and Sunil Nimmagadda.] I find the backup files mg creates scattered around a pain but then again I don't want to switch backups off since they can be useful. Also, I don't feel the need to implement something in mg as fancy as emacs's backup functionality ie. moving backup files, versioning, deleting old backup versions etc With this diff I've only added the emacs functionality of moving the backup files to a single directory instead of having them scattered around everywhere. There are some drawbacks to having the backups in one directory of course, only one backup version is maintained for files of the same name but which originate in different directories (But that is enough for me) Since the functionality isn't trying to mimic emacs exactly, the command name I've chosen isn't trying to reuse one of emacs'. backup-to-home-directory This is open to suggestions of course. The backup directory name ~/.mg.d stems from emacs's ~/.emacs.d. Any comments? -lum Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.123 diff -u -p -r1.123 def.h --- def.h 7 Jun 2012 15:15:04 - 1.123 +++ def.h 7 Jun 2012 17:38:26 - @@ -446,6 +446,7 @@ struct list *make_file_list(char *); int fisdir(const char *); int fchecktime(struct buffer *); int fupdstat(struct buffer *); +int backuptohomedir(int, int); /* kbd.c X */ int do_meta(int, int); Index: fileio.c === RCS file: /cvs/src/usr.bin/mg/fileio.c,v retrieving revision 1.89 diff -u -p -r1.89 fileio.c --- fileio.c25 May 2012 04:56:58 - 1.89 +++ fileio.c7 Jun 2012 17:38:26 - @@ -22,6 +22,10 @@ #include kbd.h +static char *bkuplocation(const char *); + +static char *bkupdir; + /* * Open a file for reading. */ @@ -189,6 +193,26 @@ ffgetline(FILE *ffp, char *buf, int nbuf } /* + * Location of backup file. This function creates the correct path. + */ +static char * +bkuplocation(const char *fn) +{ + struct stat sb; + char *fname, *c; + + if (bkupdir != NULL (stat(bkupdir, sb) == 0) + S_ISDIR(sb.st_mode)) { + c = strrchr(fn, '/'); + if (asprintf(fname, %s%s, bkupdir, c) == -1) + return (NULL); + } else if ((fname = strndup(fn, NFILEN)) == NULL) + return (NULL); + + return (fname); +} + +/* * Make a backup copy of fname. On Unix the backup has the same * name as the original file, with a ~ on the end; this seems to * be newest of the new-speak. The error handling is all in file.c. @@ -203,23 +227,27 @@ fbackupfile(const char *fn) int from, to, serrno; ssize_t nread; char buf[BUFSIZ]; - char*nname, *tname; + char*nname, *tname, *bkpth; if (stat(fn, sb) == -1) { ewprintf(Can't stat %s : %s, fn, strerror(errno)); return (FALSE); } - if (asprintf(nname, %s~, fn) == -1) { + if ((bkpth = bkuplocation(fn)) == NULL) + return (FALSE); + + if (asprintf(nname, %s~, bkpth) == -1) { ewprintf(Can't allocate temp file name : %s, strerror(errno)); return (ABORT); } - if (asprintf(tname, %s.XX, fn) == -1) { + if (asprintf(tname, %s.XX, bkpth) == -1) { ewprintf(Can't allocate temp file name : %s, strerror(errno)); free(nname); return (ABORT); } + free(bkpth); if ((from = open(fn, O_RDONLY)) == -1) { free(nname); @@ -610,4 +638,28 @@ fchecktime(struct buffer *bp) return (TRUE); +} + +int +backuptohomedir(int f, int n) +{ + const char *c = ~/.mg.d; + char*p; + + if (bkupdir == NULL) { + p = adjustname(c, TRUE); + bkupdir = strndup(p, NFILEN); + if (bkupdir == NULL) + return(FALSE); + + if (mkdir(bkupdir, 0700) == -1 errno != EEXIST) { + free(bkupdir); + bkupdir = NULL; + } + } else { + free(bkupdir); + bkupdir = NULL; + } + + return (TRUE); } Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.39 diff -u -p -r1.39 funmap.c --- funmap.c7 Jun 2012 15:15:04 - 1.39 +++ funmap.c7 Jun 2012 17:38:26 - @@ -25,6 +25,7 @@ static struct funmap functnames[] = { {fillmode, auto-fill-mode,}, {indentmode, auto-indent-mode,}, {backtoindent,
mg - corner-case backward scrolling
There is a corner case when the screen buffer is only 1 line long where the loop that looks for the current dot line goes through the whole buffer until it finds the correct line. This means the line number decrement is way over what it should be. This diff accounts for that corner case. ok? -lum Index: basic.c === RCS file: /cvs/src/usr.bin/mg/basic.c,v retrieving revision 1.34 diff -u -p -r1.34 basic.c --- basic.c 1 Jun 2012 11:22:06 - 1.34 +++ basic.c 5 Jun 2012 21:01:38 - @@ -305,11 +305,12 @@ int backpage(int f, int n) { struct line *lp, *lp2; + int i = 0; if (!(f FFARG)) { n = curwp-w_ntrows - 2;/* Default scroll. */ if (n = 0) /* Don't blow up if the */ - n = 1; /* window is tiny. */ + i = n = 1; /* window is tiny. */ } else if (n 0) return (forwpage(f | FFRAND, -n)); @@ -332,10 +333,15 @@ backpage(int f, int n) lp2 = lforw(lp2); - /* Move the dot the slow way, for line nos */ - while (curwp-w_dotp != lp2) { - curwp-w_dotp = lback(curwp-w_dotp); - curwp-w_dotline--; + if (i == 1) { +curwp-w_dotp = lback(curwp-w_dotp); +curwp-w_dotline--; + } else { + /* Move the dot the slow way, for line nos */ + while (curwp-w_dotp != lp2) { + curwp-w_dotp = lback(curwp-w_dotp); + curwp-w_dotline--; + } } curwp-w_doto = 0; return (TRUE);
Re: cscope support in mg
Here is an updated diff with following changes... Manpage update. Remove conditional compilation of cscope functionality. Fixed a memory leak in csexists function. Treat current word at cursor as default input for cscope commands. Comments? I like it. I'm using your previous diffs (ctags/shell-command-on-region etc..) to develope mg, so I'm keen for it to go in. I recall others being interested in this, do they have anything to say? Or are there any objectors? mark
mg - scrolling back diff
Currently, mg's cursor jumps from top to bottom of the screen as you scroll upwards, I find this behaviour confusing at times. This diff makes mg's scroll back the same as emacs. Comments/ok? mark Index: basic.c === RCS file: /cvs/src/usr.bin/mg/basic.c,v retrieving revision 1.32 diff -u -p -r1.32 basic.c --- basic.c 30 May 2012 06:13:32 - 1.32 +++ basic.c 31 May 2012 06:57:11 - @@ -301,7 +301,7 @@ forwpage(int f, int n) int backpage(int f, int n) { - struct line *lp; + struct line *lp, *lp2; if (!(f FFARG)) { n = curwp-w_ntrows - 2;/* Default scroll. */ @@ -309,18 +309,24 @@ backpage(int f, int n) n = 1; /* window is tiny. */ } else if (n 0) return (forwpage(f | FFRAND, -n)); - lp = curwp-w_linep; + + lp = lp2 = curwp-w_linep; + while (n-- lback(lp) != curbp-b_headp) { lp = lback(lp); } curwp-w_linep = lp; curwp-w_rflag |= WFFULL; + /* if in current window, don't move dot */ for (n = curwp-w_ntrows; n-- lp != curbp-b_headp; lp = lforw(lp)) if (lp == curwp-w_dotp) return (TRUE); + +lp2 = lforw(lp2); + /* Move the dot the slow way, for line nos */ - while (curwp-w_dotp != curwp-w_linep) { + while (curwp-w_dotp != lp2) { curwp-w_dotp = lback(curwp-w_dotp); curwp-w_dotline--; }
mg - more emacs scroll compatibility
Show a message and beep when you reach either end of a buffer. ok? -lum Index: basic.c === RCS file: /cvs/src/usr.bin/mg/basic.c,v retrieving revision 1.33 diff -u -p -r1.33 basic.c --- basic.c 31 May 2012 10:55:53 - 1.33 +++ basic.c 31 May 2012 14:54:24 - @@ -269,8 +269,11 @@ forwpage(int f, int n) lp = curwp-w_linep; while (n--) - if ((lp = lforw(lp)) == curbp-b_headp) + if ((lp = lforw(lp)) == curbp-b_headp) { + ttbeep(); + ewprintf(End of buffer); return(TRUE); + } curwp-w_linep = lp; curwp-w_rflag |= WFFULL; @@ -314,6 +317,10 @@ backpage(int f, int n) while (n-- lback(lp) != curbp-b_headp) { lp = lback(lp); + } + if (lp == curwp-w_linep) { + ttbeep(); + ewprintf(Beginning of buffer); } curwp-w_linep = lp; curwp-w_rflag |= WFFULL;
mg - remove *init* buffer
After a recent commit (http://marc.info/?l=openbsd-techm=133787310204563w=2) I realised the *init* buffer could be removed since we went back and updated modes after scratch was created. There is a side effect to this diff; theo mode now works from the command line: $ mg -f theo [it had been broken for a while] Comments/ok -lum Index: main.c === RCS file: /cvs/src/usr.bin/mg/main.c,v retrieving revision 1.65 diff -u -p -r1.65 main.c --- main.c 25 May 2012 05:05:48 - 1.65 +++ main.c 28 May 2012 14:09:51 - @@ -23,7 +23,7 @@ struct mgwin *curwp; /* current windo struct mgwin *wheadp;/* MGWIN listhead */ charpat[NPAT]; /* pattern */ -static void edinit(PF); +static void edinit(struct buffer *); static __dead void usage(void); extern char*__progname; @@ -40,11 +40,11 @@ usage() int main(int argc, char **argv) { - char*cp, *init_fcn_name = NULL; - PF init_fcn = NULL; - int o, i, nfiles; - int nobackups = 0; - struct buffer *bp; + char*cp, *init_fcn_name = NULL; + PF init_fcn = NULL; + int o, i, nfiles; + int nobackups = 0; + struct buffer *bp = NULL; while ((o = getopt(argc, argv, nf:)) != -1) switch (o) { @@ -88,7 +88,7 @@ main(int argc, char **argv) vtinit(); /* Virtual terminal.*/ dirinit(); /* Get current directory. */ - edinit(init_fcn); /* Buffers, windows.*/ + edinit(bp); /* Buffers, windows.*/ ttykeymapinit();/* Symbols, bindings. */ /* @@ -98,13 +98,6 @@ main(int argc, char **argv) */ update(); - /* -* Create scratch buffer now, killing old *init* buffer. -* This causes *scratch* to be created and made curbp. -*/ - if ((bp = bfind(*init*, FALSE)) != NULL) - killbuffer(bp); - /* user startup file. */ if ((cp = startupfile(NULL)) != NULL) (void)load(cp); @@ -194,26 +187,23 @@ notnum: } /* - * Initialize default buffer and window. - * Initially, buffer is named *init*. This is changed later - * to *scratch* after the startup files are read. + * Initialize default buffer and window. Default buffer is called *scratch*. */ static void -edinit(PF init_fcn) +edinit(struct buffer *bp) { - struct buffer *bp; struct mgwin*wp; bheadp = NULL; - bp = bfind(*init*, TRUE); /* Text buffer. */ + bp = bfind(*scratch*, TRUE); /* Text buffer. */ if (bp == NULL) panic(edinit); wp = new_window(bp); if (wp == NULL) - panic(Out of memory); + panic(edinit: Out of memory); - curbp = bp; /* Current ones. */ + curbp = bp; /* Current buffer. */ wheadp = wp; curwp = wp; wp-w_wndp = NULL; /* Initialize window.*/
mg end of buffer page down diff
When you page down a document and get to the last page, mg doesn't stop, it keeps going until the last line is at the top of the window. This diff makes mg stop paging down when the end of the text is visible. Comments/ok? -lum ps some whitespace for readability added. Index: basic.c === RCS file: /cvs/src/usr.bin/mg/basic.c,v retrieving revision 1.30 diff -u -p -r1.30 basic.c --- basic.c 4 Jun 2009 02:23:37 - 1.30 +++ basic.c 25 May 2012 07:40:33 - @@ -266,16 +266,20 @@ forwpage(int f, int n) n = 1; /* if tiny window. */ } else if (n 0) return (backpage(f | FFRAND, -n)); + lp = curwp-w_linep; - while (n-- lforw(lp) != curbp-b_headp) { - lp = lforw(lp); - } + while (n--) + if ((lp = lforw(lp)) == curbp-b_headp) + return(TRUE); + curwp-w_linep = lp; curwp-w_rflag |= WFFULL; + /* if in current window, don't move dot */ - for (n = curwp-w_ntrows; n-- lp != curbp-b_headp; lp = lforw(lp)) + for (n = curwp-w_ntrows; n--; lp = lforw(lp)) if (lp == curwp-w_dotp) return (TRUE); + /* Advance the dot the slow way, for line nos */ while (curwp-w_dotp != curwp-w_linep) { curwp-w_dotp = lforw(curwp-w_dotp);
mg history and window relocation
Move the windows section in the tutorial to a more sensible place (next to buffers) and move the mg history into the README file which seems a more sensible place as well. ok? -lum Index: README === RCS file: /cvs/src/usr.bin/mg/README,v retrieving revision 1.9 diff -u -p -r1.9 README --- README 11 Apr 2012 17:51:10 - 1.9 +++ README 25 May 2012 10:30:31 - @@ -40,8 +40,16 @@ People who have worked on previous versi rtech!da...@sun.com Dave Brower -Currently maintained in the OpenBSD src tree, with contributions from -many others. +Early release history: + +* Nov 16, 1986: First release to mod.sources +* Mar 3, 1987: First Release (mg1a) via comp.sources.unix +* May 26, 1988: Second release: (mg2a) via comp.sources.misc +* Jan 26, 1992: Linux port released by Charles Hedrick. This version + later makes its way onto tsx-11, Infomagic, and various other Linux + repositories. +* Feb 25, 2000: First import into the OpenBSD tree, where it is + currently maintained. -- Index: tutorial === RCS file: /cvs/src/usr.bin/mg/tutorial,v retrieving revision 1.9 diff -u -p -r1.9 tutorial --- tutorial7 May 2012 13:52:58 - 1.9 +++ tutorial25 May 2012 10:30:32 - @@ -118,20 +118,6 @@ screen when you type C-g indicating that In general, when in doubt, use C-g to get out of trouble. -Windows - -The mg editor can support several windows at the same time, each one displaying -different text. To split a screen into two horizontal windows use C-x 2 to do -this. To return to one window, use C-x 1 to close the other windows and only -keep the current window. - - Use C-x 2 to split the screen into two windows. - - Use C-x o to move from one window to the other. You can scroll up and down - in each window using the cursor keys or C-n and C-p keys. - - Use C-x 1 to restore back to one window. Inserting/Deleting Text --- @@ -267,6 +253,21 @@ in the bottom of your screen. In general often. When you save a file, mg saves a backup of the file with a tilde (~) character at the end. +Windows +--- + +The mg editor can support several windows at the same time, each one displaying +different text. To split a screen into two horizontal windows use C-x 2 to do +this. To return to one window, use C-x 1 to close the other windows and only +keep the current window. + + Use C-x 2 to split the screen into two windows. + + Use C-x o to move from one window to the other. You can scroll up and down + in each window using the cursor keys or C-n and C-p keys. + + Use C-x 1 to restore back to one window. + Buffers --- @@ -334,31 +335,11 @@ information available via the mg(1) man improvement, please don't hesitate to drop a message or (better still) submit a diff to tech@openbsd.org. -History - -mg is a public-domain text editor. It was originally based on MicroEMACS, but -has since moved to more closely resemble GNU Emacs while still maintaining a -small memory footprint and fast speed. - -* Nov 16, 1986: First release to mod.sources -* Mar 3, 1987: First Release (mg1a) via comp.sources.unix -* May 26, 1988: Second release: (mg2a) via comp.sources.misc -* Jan 26, 1992: Linux port released by Charles Hedrick. This version - later makes its way onto tsx-11, Infomagic, and various other Linux - repositories. -* Feb 25, 2000: First import into the OpenBSD tree, where it is - currently maintained - -The mg editor was originally named MicroGNUEmacs. The name was changed at -the request of Richard Stallman, as this software is entirely unrelated to -the GNU project. - Author Info --- Original Author of this document: Mayukh Bose, -Date last updated: 2012-01-17 +Date last updated: 2012-05-25 Copyright -