diff --git a/libguile/readline.c b/libguile/readline.c index ea8c2295e..90d2b5268 100644 --- a/libguile/readline.c +++ b/libguile/readline.c @@ -50,11 +50,17 @@ #include #include +#include +#include "iselect.h" + + scm_option scm_readline_opts[] = { { SCM_OPTION_BOOLEAN, "history-file", 1, "Use history file." }, { SCM_OPTION_INTEGER, "history-length", 200, - "History length." } + "History length." }, + { SCM_OPTION_INTEGER, "bounce-parens", 500, + "Time (ms) to show matching opening parenthesis (0 = off)."} }; extern void stifle_history (int max); @@ -155,9 +161,9 @@ redisplay () SCM_PROC (s_readline, "readline", 0, 4, 0, scm_readline); -int in_readline = 0; +static int in_readline = 0; #ifdef USE_THREADS -scm_mutex_t reentry_barrier_mutex; +static scm_mutex_t reentry_barrier_mutex; #endif static void @@ -360,6 +366,94 @@ completion_function (char *text, int continuep) } } +/*Bouncing parenthesis (reimplemented by GH, 11/23/98, since readline is strict gpl)*/ + +static void match_paren(int x, int k); +static int find_matching_paren(int k); +static void init_bouncing_parens(); + +static void +init_bouncing_parens() +{ + if(strncmp(rl_get_keymap_name(rl_get_keymap()), "vi", 2)) { + rl_bind_key(')', match_paren); + rl_bind_key(']', match_paren); + rl_bind_key('}', match_paren); + } +} + +static int +find_matching_paren(int k) +{ + register int i; + register char c = 0; + int end_parens_found = 0; + + /* Choose the corresponding opening bracket. */ + if (k == ')') c = '('; + else if (k == ']') c = '['; + else if (k == '}') c = '{'; + + for (i=rl_point-2; i>=0; i--) + { + /* Is the current character part of a character literal? */ + if (i - 2 >= 0 + && rl_line_buffer[i - 1] == '\\' + && rl_line_buffer[i - 2] == '#') + ; + else if (rl_line_buffer[i] == k) + end_parens_found++; + else if (rl_line_buffer[i] == '"') + { + /* Skip over a string literal. */ + for (i--; i >= 0; i--) + if (rl_line_buffer[i] == '"' + && ! (i - 1 >= 0 + && rl_line_buffer[i - 1] == '\\')) + break; + } + else if (rl_line_buffer[i] == c) + { + if (end_parens_found==0) return i; + else --end_parens_found; + } + } + return -1; +} + +static void +match_paren(int x, int k) +{ + int tmp; + fd_set readset; + struct timeval timeout; + + rl_insert(x, k); + if (!SCM_READLINE_BOUNCE_PARENS) + return; + + /* Did we just insert a quoted paren? If so, then don't bounce. */ + if (rl_point - 1 >= 1 + && rl_line_buffer[rl_point - 2] == '\\') + return; + + tmp = 1000 * SCM_READLINE_BOUNCE_PARENS; + timeout.tv_sec = tmp / 1000000; + timeout.tv_usec = tmp % 1000000; + FD_ZERO(&readset); + FD_SET(fileno(rl_instream), &readset); + + if(rl_point > 1) { + tmp = rl_point; + rl_point = find_matching_paren(k); + if(rl_point > -1) { + rl_redisplay(); + scm_internal_select(1, &readset, NULL, NULL, &timeout); + } + rl_point = tmp; + } +} + void scm_init_readline () @@ -377,6 +471,7 @@ scm_init_readline () scm_init_opts (scm_readline_options, scm_readline_opts, SCM_N_READLINE_OPTIONS); + init_bouncing_parens(); scm_add_feature ("readline"); } diff --git a/libguile/readline.h b/libguile/readline.h index c29a4ba26..e69de29bb 100644 --- a/libguile/readline.h +++ b/libguile/readline.h @@ -1,61 +0,0 @@ -#ifndef READLINEH -#define READLINEH - -/* Copyright (C) 1997 Free Software Foundation, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * As a special exception, the Free Software Foundation gives permission - * for additional uses of the text contained in its release of GUILE. - * - * The exception is that, if you link the GUILE library with other files - * to produce an executable, this does not by itself cause the - * resulting executable to be covered by the GNU General Public License. - * Your use of that executable is in no way restricted on account of - * linking the GUILE library code into it. - * - * This exception does not however invalidate any other reasons why - * the executable file might be covered by the GNU General Public License. - * - * This exception applies only to the code released by the - * Free Software Foundation under the name GUILE. If you copy - * code from other Free Software Foundation releases into a copy of - * GUILE, as the General Public License permits, the exception does - * not apply to the code that you add in this way. To avoid misleading - * anyone as to the status of such modified files, you must delete - * this exception notice from them. - * - * If you write modifications of your own for GUILE, it is your choice - * whether to permit this exception to apply to your modifications. - * If you do not wish that, delete this exception notice. - */ - -#include "libguile/__scm.h" - -extern scm_option scm_readline_opts[]; - -#define SCM_HISTORY_FILE_P scm_readline_opts[0].val -#define SCM_HISTORY_LENGTH scm_readline_opts[1].val -#define SCM_N_READLINE_OPTIONS 2 - -extern SCM scm_readline_options (SCM setting); -extern SCM scm_readline (SCM txt, SCM inp, SCM outp, SCM read_hook); -extern SCM scm_add_history (SCM txt); -extern SCM scm_read_history (SCM file); -extern SCM scm_write_history (SCM file); -extern SCM scm_filename_completion_function (SCM text, SCM continuep); -extern void scm_init_readline (void); - -#endif