[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openbsd-tech
Subject:    Hooks in mg
From:       Sunil Nimmagadda <sunil () sunilnimmagadda ! com>
Date:       2012-02-22 19:17:00
Message-ID: 20120222190500.GA24269 () puffy
[Download RAW message or body]

Hello,

This diff generalize the hooks execution and allows to define new hook
execution points. For example if your .mg is now...

auto-execute *.c c-mode

then with this diff you can change it to...

add-hook find-file-hook c-mode
add-hook before-save-hook deltrailspace

find-file-hook type hooks get executed every time a file is read in
and before-save-hook type hooks get executed when a buffer is about to
be saved. deltrailspace is a hook that removes trailing whitespace before
saving a buffer whose filename matches *.[ch1-9]

comments?

Index: Makefile
===================================================================
RCS file: /home/sunil/cvs/src/usr.bin/mg/Makefile,v
retrieving revision 1.25
diff -u -p -r1.25 Makefile
--- Makefile	28 Nov 2011 04:41:39 -0000	1.25
+++ Makefile	22 Feb 2012 18:06:59 -0000
@@ -24,7 +24,7 @@ SRCS=	autoexec.c basic.c buffer.c cinfo.
 #
 # More or less standalone extensions.
 #
-SRCS+=	cmode.c dired.c grep.c tags.c theo.c
+SRCS+=	cmode.c dired.c hookexec.c hooks.c grep.c tags.c theo.c
 
 afterinstall:
 	${INSTALL} -d ${DESTDIR}${DOCDIR}/mg
Index: def.h
===================================================================
RCS file: /home/sunil/cvs/src/usr.bin/mg/def.h,v
retrieving revision 1.118
diff -u -p -r1.118 def.h
--- def.h	10 Dec 2011 14:09:48 -0000	1.118
+++ def.h	22 Feb 2012 18:09:04 -0000
@@ -654,6 +654,19 @@ int		 next_error(int, int);
 int		 globalwdtoggle(int, int);
 int		 compile(int, int);
 
+/* hooks.c */
+void		cmode_hook(void);
+void		deltspace_hook(void);
+
+/* hookexec.c */
+enum hooktype {
+	HOOKTYPE_UNDEF,
+	HOOKTYPE_FIND_FILE,
+	HOOKTYPE_BEFORE_SAVE
+};
+int		addhook(int, int);
+void		exechooks(enum hooktype);
+
 /*
  * Externals.
  */
Index: file.c
===================================================================
RCS file: /home/sunil/cvs/src/usr.bin/mg/file.c,v
retrieving revision 1.76
diff -u -p -r1.76 file.c
--- file.c	31 Aug 2011 08:58:29 -0000	1.76
+++ file.c	22 Feb 2012 18:11:38 -0000
@@ -238,6 +238,8 @@ readin(char *fname)
 		free(ael);
 	}
 
+	exechooks(HOOKTYPE_FIND_FILE);
+
 	/* no change */
 	curbp->b_flag &= ~BFCHG;
 
@@ -572,6 +574,8 @@ buffsave(struct buffer *bp)
 			return (s);
 	}
 	
+	exechooks(HOOKTYPE_BEFORE_SAVE);
+
 	if (makebackup && (bp->b_flag & BFBAK)) {
 		s = fbackupfile(bp->b_fname);
 		/* hard error */
Index: funmap.c
===================================================================
RCS file: /home/sunil/cvs/src/usr.bin/mg/funmap.c,v
retrieving revision 1.35
diff -u -p -r1.35 funmap.c
--- funmap.c	28 Nov 2011 04:41:39 -0000	1.35
+++ funmap.c	22 Feb 2012 18:13:32 -0000
@@ -21,6 +21,7 @@ static struct funmap *funs;
 
 static struct funmap functnames[] = {
 #ifndef	NO_HELP
+	{addhook, "add-hook",},
 	{apropos_command, "apropos",},
 #endif /* !NO_HELP */
 	{auto_execute, "auto-execute", },
Index: hookexec.c
===================================================================
RCS file: hookexec.c
diff -N hookexec.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ hookexec.c	22 Feb 2012 19:00:40 -0000
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2012 Sunil Nimmagadda <sunil@sunilnimmagadda.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/queue.h>
+#include <sys/tree.h>
+
+#include "def.h"
+
+struct hook;
+typedef void (*HF)(void);
+
+static int  hcmp(struct hook *, struct hook *);
+static enum hooktype hlookup(char *);
+static int  addhook_helper(enum hooktype, HF);
+static HF   hfunction(const char *);
+
+struct hfname
+{
+	HF fp;
+	const char *name;	
+};
+
+static struct hfname hfuncnames [] = {
+	{cmode_hook, "c-mode"},
+	{deltspace_hook, "deltrailspace"},
+	{NULL, NULL}
+};
+
+struct hookfunc {
+	SLIST_ENTRY(hookfunc) entry;
+	HF                    fp;
+};
+	
+struct hook {
+	RB_ENTRY(hook)         entry;
+	SLIST_HEAD(, hookfunc) hfuncs;
+	enum hooktype          t;
+
+};
+
+/* key is enum hooktype and value is a list of HF. */
+static RB_HEAD(hookmap, hook) hmap = RB_INITIALIZER(&hmap);
+RB_GENERATE(hookmap, hook, entry, hcmp);
+
+int
+hcmp(struct hook *h1, struct hook *h2)
+{
+	return (h1->t != h2->t);
+}
+
+/*
+ * Determine hooktype, hookfunction and add it to the tree.
+ */
+/* ARGSUSED */
+int
+addhook(int f, int n)
+{
+	char buf[NXNAME], *hfuncname, *htname;
+	enum hooktype ht;
+	HF fp;
+	
+	htname = eread("hook type: ", buf, NXNAME, EFNEW);
+	if (htname == NULL)
+		return (FALSE);
+	else if ((ht = hlookup(htname)) == HOOKTYPE_UNDEF)
+		return (FALSE);
+		
+	hfuncname = eread("command: ", buf, NXNAME, EFNEW);
+	if (hfuncname == NULL)
+		return (FALSE);
+	else if ((fp = hfunction(hfuncname)) == NULL)
+		return (FALSE);
+
+	return addhook_helper(ht, fp);
+}
+
+/*
+ * Helper function to add an entry to tree. If hooktype not present
+ * in tree initialize list and add fp else just append fp to the list.
+ */
+int
+addhook_helper(enum hooktype t, HF fp)
+{
+	struct hook h, *hnew, *res;
+	struct hookfunc *hf;
+	
+	if((hf = malloc(sizeof *hf)) == NULL)
+		return (FALSE);
+	hf->fp = fp;
+	h.t = t;
+	if ((res = RB_FIND(hookmap, &hmap, &h)) == NULL) {
+		if ((hnew = malloc(sizeof *hnew)) == NULL)
+			goto cleanup;
+		hnew->t = t;
+		SLIST_INIT(&hnew->hfuncs);
+		SLIST_INSERT_HEAD(&hnew->hfuncs, hf, entry);
+		RB_INSERT(hookmap, &hmap, hnew);
+	} else
+		SLIST_INSERT_HEAD(&res->hfuncs, hf, entry);
+	return (TRUE);
+cleanup:
+	free(hf);
+	return (FALSE);
+}
+
+/*
+ * For a given hooktype find the list of functions in tree and
+ * execute them sequentially.
+ */
+void
+exechooks(enum hooktype t)
+{
+	struct hook h, *res;
+	struct hookfunc *hf;
+	
+	h.t = t;
+	if ((res = RB_FIND(hookmap, &hmap, &h)) == NULL)
+		return;
+	SLIST_FOREACH(hf, &res->hfuncs, entry)
+		(hf->fp)();
+}
+
+enum hooktype
+hlookup(char *s)
+{
+	if (strcmp(s, "before-save-hook") == 0)
+		return (HOOKTYPE_BEFORE_SAVE);
+	else if (strcmp(s, "find-file-hook") == 0)
+		return (HOOKTYPE_FIND_FILE);
+	
+	return (HOOKTYPE_UNDEF);
+}
+
+HF
+hfunction(const char *name)
+{
+	struct hfname *p;
+
+	/* Linear lookup since we have very few hooks for now */
+	for (p = hfuncnames; p->name != NULL; p++)
+		if (strcmp(p->name, name) == 0)
+			return (p->fp);
+	return (NULL);
+}
Index: hooks.c
===================================================================
RCS file: hooks.c
diff -N hooks.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ hooks.c	22 Feb 2012 18:31:43 -0000
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012 Sunil Nimmagadda <sunil@sunilnimmagadda.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ctype.h>
+#include <fnmatch.h>
+
+#include "def.h"
+
+static void ttrim(struct line *);
+
+/*
+ * Enable c-mode for C files.
+ */
+void
+cmode_hook(void)
+{
+	if (fnmatch("*.c", curbp->b_fname, 0) == 0)
+		cmode(0, 1);
+}
+
+/*
+ * Delete trailing whitespace for C and manpage sources.
+ */
+void
+deltspace_hook(void)
+{
+	struct line *lp;
+	
+	lp = curbp->b_headp;
+	if (fnmatch("*.[ch1-9]", curbp->b_fname, 0) != 0)
+		return;
+	for (lp = bfirstlp(curbp); lp != curbp->b_headp; lp = lforw(lp))
+		if (lp->l_text != NULL)
+			ttrim(lp);
+}
+
+/*
+ * Lines are not NUL terminated, reduce l_used to actually trim.
+ */
+void
+ttrim(struct line *lp)
+{
+	char *s;
+
+	s = lp->l_text + lp->l_used - 1;
+	while (isspace(*s) && s-- > lp->l_text)
+		lp->l_used--;
+}

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic