aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--lib/lexer.tes21
-rw-r--r--lib/lexers/batch.tes4
-rw-r--r--lib/lexers/cmake.tes4
-rw-r--r--lib/lexers/cpp.tes4
-rw-r--r--lib/lexers/make.tes4
-rw-r--r--lib/lexers/patch.tes4
-rw-r--r--lib/lexers/sh.tes4
-rw-r--r--lib/lexers/xml.tes4
-rw-r--r--src/Makefile.am1
-rw-r--r--src/cmdline.cpp1
-rw-r--r--src/glob.cpp152
-rw-r--r--src/glob.h66
-rw-r--r--src/parser.cpp2
-rw-r--r--src/ring.cpp41
-rw-r--r--src/ring.h6
15 files changed, 244 insertions, 74 deletions
diff --git a/lib/lexer.tes b/lib/lexer.tes
index 01c3bf1..0a4622c 100644
--- a/lib/lexer.tes
+++ b/lib/lexer.tes
@@ -19,14 +19,19 @@
:M[color.error],35M[color.set]
}
-! individual tests are appended by the lexers/*.tes files !
-EMQ[$SCITECOPATH]/lexers/batch.tes
-EMQ[$SCITECOPATH]/lexers/cmake.tes
-EMQ[$SCITECOPATH]/lexers/cpp.tes
-EMQ[$SCITECOPATH]/lexers/make.tes
-EMQ[$SCITECOPATH]/lexers/patch.tes
-EMQ[$SCITECOPATH]/lexers/sh.tes
-EMQ[$SCITECOPATH]/lexers/xml.tes
+! Automatically mung all the lexers and them to "lexer.auto" !
+Q*U.#cd EQ.[lexers]
+ENQ[$SCITECOPATH]/lexers/*.tes J
+<:L;R
+ 0X.[filename] .-4U.p -S/ .,Q.pX.[name]
+ EMQ.[filename]
+ EQ[lexer.auto] ZJ
+ @I{
+ :M[lexer.test.Q.[name]]"S :M[lexer.set.Q.[name]] Oend '
+ }
+ EQ.[lexers]
+L>
+Q.#cdEB
! append an "end" label !
:[lexer.auto]!end!
diff --git a/lib/lexers/batch.tes b/lib/lexers/batch.tes
index 7175a6c..000910d 100644
--- a/lib/lexers/batch.tes
+++ b/lib/lexers/batch.tes
@@ -21,7 +21,3 @@
:M[color.variable],6M[color.set]
:M[color.operator],7M[color.set]
}
-
-@:[lexer.auto]{
- :M[lexer.test.batch]"S :M[lexer.set.batch] Oend '
-}
diff --git a/lib/lexers/cmake.tes b/lib/lexers/cmake.tes
index 435a357..02728e5 100644
--- a/lib/lexers/cmake.tes
+++ b/lib/lexers/cmake.tes
@@ -75,7 +75,3 @@
:M[color.variable],13M[color.set]
:M[color.number],14M[color.set]
}
-
-@:[lexer.auto]{
- :M[lexer.test.cmake]"S :M[lexer.set.cmake] Oend '
-}
diff --git a/lib/lexers/cpp.tes b/lib/lexers/cpp.tes
index f07555a..8d7cee8 100644
--- a/lib/lexers/cpp.tes
+++ b/lib/lexers/cpp.tes
@@ -37,7 +37,3 @@
:M[color.preproc],9M[color.set]
:M[color.operator],10M[color.set]
}
-
-@:[lexer.auto]{
- :M[lexer.test.cpp]"S :M[lexer.set.cpp] Oend '
-}
diff --git a/lib/lexers/make.tes b/lib/lexers/make.tes
index 48ad886..bf7a973 100644
--- a/lib/lexers/make.tes
+++ b/lib/lexers/make.tes
@@ -13,7 +13,3 @@
:M[color.target],5M[color.set]
:M[color.error],6M[color.set]
}
-
-@:[lexer.auto]{
- :M[lexer.test.make]"S :M[lexer.set.make] Oend '
-}
diff --git a/lib/lexers/patch.tes b/lib/lexers/patch.tes
index 2a7204d..20670c1 100644
--- a/lib/lexers/patch.tes
+++ b/lib/lexers/patch.tes
@@ -14,7 +14,3 @@
:M[color.addition],6M[color.set]
:M[color.change],7M[color.set]
}
-
-@:[lexer.auto]{
- :M[lexer.test.patch]"S :M[lexer.set.patch] Oend '
-}
diff --git a/lib/lexers/sh.tes b/lib/lexers/sh.tes
index 7d4f14c..5e853d0 100644
--- a/lib/lexers/sh.tes
+++ b/lib/lexers/sh.tes
@@ -48,7 +48,3 @@
:M[color.variable],10M[color.set]
:M[color.string2],11M[color.set] ! Backticks !
}
-
-@:[lexer.auto]{
- :M[lexer.test.sh]"S :M[lexer.set.sh] Oend '
-}
diff --git a/lib/lexers/xml.tes b/lib/lexers/xml.tes
index de82542..30094ea 100644
--- a/lib/lexers/xml.tes
+++ b/lib/lexers/xml.tes
@@ -23,7 +23,3 @@
:M[color.preproc2],13M[color.set] ! PI !
:M[color.string2],14M[color.set] ! CDATA !
}
-
-@:[lexer.auto]{
- :M[lexer.test.xml]"S :M[lexer.set.xml] Oend '
-}
diff --git a/src/Makefile.am b/src/Makefile.am
index af324e0..d02c0b5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -30,6 +30,7 @@ libsciteco_base_a_SOURCES = main.cpp sciteco.h \
parser.cpp parser.h \
search.cpp search.h \
spawn.cpp spawn.h \
+ glob.cpp glob.h \
goto.cpp goto.h \
rbtree.cpp rbtree.h \
symbols.cpp symbols.h \
diff --git a/src/cmdline.cpp b/src/cmdline.cpp
index e78db60..8b2d412 100644
--- a/src/cmdline.cpp
+++ b/src/cmdline.cpp
@@ -36,6 +36,7 @@
#include "undo.h"
#include "symbols.h"
#include "spawn.h"
+#include "glob.h"
#include "error.h"
#include "cmdline.h"
diff --git a/src/glob.cpp b/src/glob.cpp
new file mode 100644
index 0000000..71100b7
--- /dev/null
+++ b/src/glob.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2012-2014 Robin Haberkorn
+ *
+ * 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 3 of the License, 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 program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+
+#include "sciteco.h"
+#include "interface.h"
+#include "parser.h"
+#include "ring.h"
+#include "glob.h"
+
+namespace SciTECO {
+
+namespace States {
+ StateGlob glob;
+}
+
+Globber::Globber(const gchar *_pattern)
+{
+ gchar *basename;
+
+ dirname = g_path_get_dirname(_pattern);
+ dir = g_dir_open(dirname, 0, NULL);
+
+ basename = g_path_get_basename(_pattern);
+ pattern = g_pattern_spec_new(basename);
+ g_free(basename);
+}
+
+gchar *
+Globber::next(void)
+{
+ const gchar *basename;
+
+ while ((basename = g_dir_read_name(dir)))
+ if (g_pattern_match_string(pattern, basename))
+ return g_build_filename(dirname, basename, NIL);
+
+ return NULL;
+}
+
+Globber::~Globber()
+{
+ if (pattern)
+ g_pattern_spec_free(pattern);
+ if (dir)
+ g_dir_close(dir);
+ g_free(dirname);
+}
+
+/*
+ * Command States
+ */
+
+/*$
+ * EN[pattern]$ -- Get list of files matching a glob pattern
+ *
+ * The EN command expands a glob \fIpattern\fP to a list of
+ * matching file names. This is similar to globbing
+ * on UNIX but not as powerful.
+ * A \fIpattern\fP is a file name with \(lq*\(rq and
+ * \(lq?\(rq wildcards:
+ * \(lq*\(rq matches an arbitrary, possibly empty, string.
+ * \(lq?\(rq matches an arbitrary character.
+ *
+ * EN will currently only match files in the file name component
+ * of \fIpattern\fP, not on each component of the path name
+ * separately.
+ * In other words, EN only looks through the directory
+ * of \fIpattern\fP \(em you cannot effectively match
+ * multiple directories.
+ *
+ * The result of the globbing is inserted into the current
+ * document, at the current position.
+ * A linefeed is inserted after every file name, i.e.
+ * every matching file will be on its own line.
+ *
+ * String-building characters are enabled for EN.
+ */
+/*
+ * NOTE: This does not work like classic TECO's
+ * EN command (iterative globbing), since the
+ * position in the directory cannot be reasonably
+ * reset on rubout with glib's API.
+ * If we have to perform all the globbing on initialization
+ * we can just as well return all the results at once.
+ * And we can add them to the current document since
+ * when they should be in a register, the user will
+ * have to edit that register anyway.
+ */
+State *
+StateGlob::done(const gchar *str)
+{
+ BEGIN_EXEC(&States::start);
+
+ Globber globber(str);
+
+ gchar *filename;
+ bool text_added = false;
+
+ interface.ssm(SCI_BEGINUNDOACTION);
+
+ while ((filename = globber.next())) {
+ size_t len = strlen(filename);
+ /* overwrite trailing null */
+ filename[len] = '\n';
+
+ /*
+ * FIXME: Once we're 8-bit clean, we should
+ * add the filenames null-terminated
+ * (there may be linebreaks in filename).
+ */
+ interface.ssm(SCI_ADDTEXT, len+1,
+ (sptr_t)filename);
+
+ g_free(filename);
+ text_added = true;
+ }
+
+ interface.ssm(SCI_SCROLLCARET);
+ interface.ssm(SCI_ENDUNDOACTION);
+
+ if (text_added) {
+ ring.dirtify();
+ if (current_doc_must_undo())
+ interface.undo_ssm(SCI_UNDO);
+ }
+
+ return &States::start;
+}
+
+} /* namespace SciTECO */
diff --git a/src/glob.h b/src/glob.h
new file mode 100644
index 0000000..6652d1d
--- /dev/null
+++ b/src/glob.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012-2014 Robin Haberkorn
+ *
+ * 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 3 of the License, 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 program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GLOB_H
+#define __GLOB_H
+
+#include <string.h>
+
+#include <glib.h>
+
+#include "sciteco.h"
+#include "parser.h"
+
+namespace SciTECO {
+
+/*
+ * Auxiliary functions
+ */
+static inline bool
+is_glob_pattern(const gchar *str)
+{
+ return strchr(str, '*') || strchr(str, '?');
+}
+
+class Globber {
+ gchar *dirname;
+ GDir *dir;
+ GPatternSpec *pattern;
+
+public:
+ Globber(const gchar *pattern);
+ ~Globber();
+
+ gchar *next(void);
+};
+
+/*
+ * Command states
+ */
+
+class StateGlob : public StateExpectFile {
+private:
+ State *done(const gchar *str);
+};
+
+namespace States {
+ extern StateGlob glob;
+}
+
+} /* namespace SciTECO */
+
+#endif
diff --git a/src/parser.cpp b/src/parser.cpp
index 3c991fc..6995a6b 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -37,6 +37,7 @@
#include "symbols.h"
#include "search.h"
#include "spawn.h"
+#include "glob.h"
#include "cmdline.h"
#include "error.h"
@@ -1801,6 +1802,7 @@ StateECommand::StateECommand() : State()
transitions['C'] = &States::executecommand;
transitions['G'] = &States::egcommand;
transitions['M'] = &States::macro_file;
+ transitions['N'] = &States::glob;
transitions['S'] = &States::scintilla_symbols;
transitions['Q'] = &States::eqcommand;
transitions['W'] = &States::savefile;
diff --git a/src/ring.cpp b/src/ring.cpp
index 575d0e7..03cda37 100644
--- a/src/ring.cpp
+++ b/src/ring.cpp
@@ -38,8 +38,9 @@
#include "parser.h"
#include "expressions.h"
#include "qregisters.h"
-#include "ring.h"
+#include "glob.h"
#include "error.h"
+#include "ring.h"
#ifdef HAVE_WINDOWS_H
/* here it shouldn't cause conflicts with other headers */
@@ -600,8 +601,10 @@ StateEditFile::do_edit(tecoInt id)
* Naturally this only has any effect in interactive
* mode.
*
- * <file> may also be a glob-pattern, in which case
+ * <file> may also be a glob pattern, in which case
* all files matching the pattern are opened/edited.
+ * Globbing is performed exactly the same as the
+ * EN command does.
*
* File names of buffers in the ring are normalized
* by making them absolute.
@@ -661,37 +664,11 @@ StateEditFile::done(const gchar *str)
}
if (is_glob_pattern(str)) {
- gchar *dirname;
- GDir *dir;
-
- dirname = g_path_get_dirname(str);
- dir = g_dir_open(dirname, 0, NULL);
-
- if (dir) {
- const gchar *basename;
- GPatternSpec *pattern;
-
- basename = g_path_get_basename(str);
- pattern = g_pattern_spec_new(basename);
- g_free((gchar *)basename);
-
- while ((basename = g_dir_read_name(dir))) {
- if (g_pattern_match_string(pattern, basename)) {
- gchar *filename;
-
- filename = g_build_filename(dirname,
- basename,
- NIL);
- do_edit(filename);
- g_free(filename);
- }
- }
-
- g_pattern_spec_free(pattern);
- g_dir_close(dir);
- }
+ Globber globber(str);
+ gchar *filename;
- g_free(dirname);
+ while ((filename = globber.next()))
+ do_edit(filename);
} else {
do_edit(*str ? str : NULL);
}
diff --git a/src/ring.h b/src/ring.h
index 8dc0422..b9e9ced 100644
--- a/src/ring.h
+++ b/src/ring.h
@@ -18,7 +18,6 @@
#ifndef __RING_H
#define __RING_H
-#include <string.h>
#include <bsd/sys/queue.h>
#include <glib.h>
@@ -38,11 +37,6 @@ namespace SciTECO {
/*
* Auxiliary functions
*/
-static inline bool
-is_glob_pattern(const gchar *str)
-{
- return strchr(str, '*') || strchr(str, '?');
-}
/*
* Get absolute/full version of a possibly relative path.