summaryrefslogtreecommitdiffstats
path: root/linenoise
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-09-15 20:17:08 -0700
committerKaz Kylheku <kaz@kylheku.com>2015-09-15 20:17:08 -0700
commit81709906eeb5e853d03f5e966e631720c8632566 (patch)
treeb03898133b1b967b625dbdf0391871aaea3e546b /linenoise
parentba05e309f805fa6338584aa8e77350dade9269ca (diff)
downloadtxr-81709906eeb5e853d03f5e966e631720c8632566.tar.gz
txr-81709906eeb5e853d03f5e966e631720c8632566.tar.bz2
txr-81709906eeb5e853d03f5e966e631720c8632566.zip
linenoise: parenthesis-matching backward jump.
* linenoise/linenoise.c (LINENOISE_PAREN_DELAY): New preprocessor symbol. (scan_match_rev, scan_rev, usec_delay, paren_jump): New static functions. (edit): Handle closing parenthesis, bracket and brace by inserting and calling paren_jump. * txr.1: Documented.
Diffstat (limited to 'linenoise')
-rw-r--r--linenoise/linenoise.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/linenoise/linenoise.c b/linenoise/linenoise.c
index f630c2f0..52fc4977 100644
--- a/linenoise/linenoise.c
+++ b/linenoise/linenoise.c
@@ -54,12 +54,17 @@
#include <sys/ioctl.h>
#include <unistd.h>
#include <signal.h>
+#include <time.h>
#include "config.h"
+#if HAVE_POLL
+#include <poll.h>
+#endif
#include "linenoise.h"
#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
#define LINENOISE_MAX_LINE 1024
#define LINENOISE_MAX_DISP (LINENOISE_MAX_LINE * 8)
+#define LINENOISE_PAREN_DELAY 400000
/* The lino_state structure represents the state during line editing.
* We pass this state to functions implementing specific editing
@@ -764,6 +769,88 @@ static void refresh_line(lino_t *ls) {
refresh_singleline(ls);
}
+static size_t scan_match_rev(const char *s, size_t i, int mch)
+{
+ while (i > 0) {
+ int ch = s[--i];
+
+ if (ch == mch)
+ return i;
+
+ switch (ch) {
+ case ')':
+ if ((i = scan_match_rev(s, i, '(')) == -1)
+ return -1;
+ break;
+ case ']':
+ if ((i = scan_match_rev(s, i, '[')) == -1)
+ return -1;
+ break;
+ case '}':
+ if ((i = scan_match_rev(s, i, '{')) == -1)
+ return -1;
+ break;
+ case '(': case '[': case '{':
+ return -1;
+ default:
+ break;
+ }
+ }
+
+ return -1;
+}
+
+static size_t scan_rev(const char *s, size_t i)
+{
+ switch (s[i]) {
+ case ')':
+ return scan_match_rev(s, i, '(');
+ case ']':
+ return scan_match_rev(s, i, '[');
+ case '}':
+ return scan_match_rev(s, i, '{');
+ default:
+ return -1;
+ }
+}
+
+static void usec_delay(lino_t *l, long usec)
+{
+#if HAVE_POLL
+ struct pollfd pfd;
+ pfd.fd = l->ifd;
+ pfd.events = POLLIN;
+ poll(&pfd, 1, usec/1000);
+#elif HAVE_POSIX_NANOSLEEP
+ struct timespec ts;
+ (void) l;
+ ts.tv_sec = usec / 1000000;
+ ts.tv_nsec = (usec % 1000000) * 1000;
+ nanosleep(&ts, 0);
+#elif HAVE_POSIX_USLEEP
+ (void) l;
+ if (u >= 1000000)
+ sleep(u / 1000000);
+ usleep(u % 1000000);
+#else
+#error portme
+#endif
+}
+
+static void paren_jump(lino_t *l)
+{
+ size_t pos = scan_rev(l->data, l->dpos - 1);
+
+ if (pos != -1) {
+ size_t dp = l->dpos;
+ l->dpos = pos;
+ refresh_line(l);
+ usec_delay(l, LINENOISE_PAREN_DELAY);
+ l->dpos = dp;
+ refresh_line(l);
+ }
+}
+
/* Insert the character 'c' at cursor current position.
*
* On error writing to the terminal -1 is returned, otherwise 0. */
@@ -1083,6 +1170,13 @@ static int edit(lino_t *l, const char *prompt)
}
}
break;
+ case ')': case ']': case '}':
+ if (edit_insert(l,c)) {
+ l->error = lino_ioerr;
+ return -1;
+ }
+ paren_jump(l);
+ break;
default:
if (c < 32)
break;