diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2014-11-16 19:31:29 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2014-11-16 23:34:25 +0100 |
commit | 38fcf6d15cdf09591e7d7a142ad724164875e433 (patch) | |
tree | bc6d81a5c3e33b6832cf0507fbf7e9e4a01a4358 | |
parent | 7a0857515ad216325fc3021c7490df9d01a21c7c (diff) | |
download | sciteco-38fcf6d15cdf09591e7d7a142ad724164875e433.tar.gz |
rewritten View and Interface base classes using the Curiously Recurring Template Pattern.
* without the one-view-per-buffer designs, many Scintilla send message (SSM)
calls could be inlined
* with the new design, this was no longer possible using the abstract
base classes. the CRT pattern allows inlining again but introduces
a strange level of code obscurity.
* tests suggest that at high optimization levels, the one-view-per-buffer
design and the CRT pattern reduces typical macro runtimes by 30%
(e.g. for symbols-extract.tes).
* only updated the NCurses UI for the time being
-rw-r--r-- | src/cmdline.cpp | 10 | ||||
-rw-r--r-- | src/error.cpp | 10 | ||||
-rw-r--r-- | src/interface-ncurses.cpp | 25 | ||||
-rw-r--r-- | src/interface-ncurses.h | 53 | ||||
-rw-r--r-- | src/interface.cpp | 27 | ||||
-rw-r--r-- | src/interface.h | 205 | ||||
-rw-r--r-- | src/parser.cpp | 3 | ||||
-rw-r--r-- | src/ring.cpp | 16 | ||||
-rw-r--r-- | src/search.cpp | 2 |
9 files changed, 237 insertions, 114 deletions
diff --git a/src/cmdline.cpp b/src/cmdline.cpp index 52427b8..e28ce35 100644 --- a/src/cmdline.cpp +++ b/src/cmdline.cpp @@ -247,7 +247,7 @@ process_edit_cmd(gchar key) *insert = '\0'; if (Goto::skip_label) { - interface.msg(Interface::MSG_ERROR, + interface.msg(InterfaceCurrent::MSG_ERROR, "Label \"%s\" not found", Goto::skip_label); break; @@ -420,13 +420,13 @@ filename_complete(const gchar *filename, gchar completed) for (GList *file = g_list_first(files); file != NULL; file = g_list_next(file)) { - Interface::PopupEntryType type; + InterfaceCurrent::PopupEntryType type; bool in_buffer = false; if (filename_is_dir((gchar *)file->data)) { - type = Interface::POPUP_DIRECTORY; + type = InterfaceCurrent::POPUP_DIRECTORY; } else { - type = Interface::POPUP_FILE; + type = InterfaceCurrent::POPUP_FILE; /* FIXME: inefficient */ in_buffer = ring.find((gchar *)file->data); } @@ -490,7 +490,7 @@ symbol_complete(SymbolList &list, const gchar *symbol, gchar completed) for (GList *entry = g_list_first(glist); entry != NULL; entry = g_list_next(entry)) { - interface.popup_add(Interface::POPUP_PLAIN, + interface.popup_add(InterfaceCurrent::POPUP_PLAIN, (gchar *)entry->data); } diff --git a/src/error.cpp b/src/error.cpp index a76d0e1..7bdd6f2 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -55,7 +55,7 @@ Error::QRegFrame::copy() const void Error::QRegFrame::display(gint nr) { - interface.msg(Interface::MSG_INFO, + interface.msg(InterfaceCurrent::MSG_INFO, "#%d in Q-Register \"%s\" at %d (%d:%d)", nr, name, pos, line, column); } @@ -75,7 +75,7 @@ Error::FileFrame::copy() const void Error::FileFrame::display(gint nr) { - interface.msg(Interface::MSG_INFO, + interface.msg(InterfaceCurrent::MSG_INFO, "#%d in file \"%s\" at %d (%d:%d)", nr, name, pos, line, column); } @@ -95,7 +95,7 @@ Error::ToplevelFrame::copy() const void Error::ToplevelFrame::display(gint nr) { - interface.msg(Interface::MSG_INFO, + interface.msg(InterfaceCurrent::MSG_INFO, "#%d in toplevel macro at %d (%d:%d)", nr, pos, line, column); } @@ -136,7 +136,7 @@ Error::add_frame(Frame *frame) void Error::display_short(void) { - interface.msg(Interface::MSG_ERROR, + interface.msg(InterfaceCurrent::MSG_ERROR, "%s (at %d)", description, pos); } @@ -145,7 +145,7 @@ Error::display_full(void) { gint nr = 0; - interface.msg(Interface::MSG_ERROR, "%s", description); + interface.msg(InterfaceCurrent::MSG_ERROR, "%s", description); frames = g_slist_reverse(frames); for (GSList *cur = frames; cur; cur = g_slist_next(cur)) { diff --git a/src/interface-ncurses.cpp b/src/interface-ncurses.cpp index bb88af1..0be2145 100644 --- a/src/interface-ncurses.cpp +++ b/src/interface-ncurses.cpp @@ -85,7 +85,7 @@ ViewNCurses::~ViewNCurses() } void -InterfaceNCurses::main(int &argc, char **&argv) +InterfaceNCurses::main_impl(int &argc, char **&argv) { init_screen(); cbreak(); @@ -174,7 +174,7 @@ InterfaceNCurses::resize_all_windows(void) } void -InterfaceNCurses::vmsg(MessageType type, const gchar *fmt, va_list ap) +InterfaceNCurses::vmsg_impl(MessageType type, const gchar *fmt, va_list ap) { static const chtype type2attr[] = { SCI_COLOR_ATTR(COLOR_BLACK, COLOR_WHITE), /* MSG_USER */ @@ -216,12 +216,11 @@ InterfaceNCurses::msg_clear(void) } void -InterfaceNCurses::show_view(View *view) +InterfaceNCurses::show_view_impl(ViewNCurses *view) { int lines, cols; /* screen dimensions */ - /* We know that `view` is a ViewNCurses */ - current_view = (ViewNCurses *)view; + current_view = view; /* * screen size might have changed since @@ -247,7 +246,7 @@ InterfaceNCurses::draw_info(void) } void -InterfaceNCurses::info_update(QRegister *reg) +InterfaceNCurses::info_update_impl(QRegister *reg) { g_free(info_current); info_current = g_strdup_printf("%s - <QRegister> %s", PACKAGE_NAME, @@ -257,7 +256,7 @@ InterfaceNCurses::info_update(QRegister *reg) } void -InterfaceNCurses::info_update(Buffer *buffer) +InterfaceNCurses::info_update_impl(Buffer *buffer) { g_free(info_current); info_current = g_strdup_printf("%s - <Buffer> %s%s", PACKAGE_NAME, @@ -268,7 +267,7 @@ InterfaceNCurses::info_update(Buffer *buffer) } void -InterfaceNCurses::cmdline_update(const gchar *cmdline) +InterfaceNCurses::cmdline_update_impl(const gchar *cmdline) { size_t len; int half_line = (getmaxx(stdscr) - 2) / 2; @@ -294,8 +293,8 @@ InterfaceNCurses::cmdline_update(const gchar *cmdline) } void -InterfaceNCurses::popup_add(PopupEntryType type, - const gchar *name, bool highlight) +InterfaceNCurses::popup_add_impl(PopupEntryType type, + const gchar *name, bool highlight) { gchar *entry; @@ -311,7 +310,7 @@ InterfaceNCurses::popup_add(PopupEntryType type, } void -InterfaceNCurses::popup_show(void) +InterfaceNCurses::popup_show_impl(void) { int lines, cols; /* screen dimensions */ int popup_lines; @@ -374,7 +373,7 @@ cleanup: } void -InterfaceNCurses::popup_clear(void) +InterfaceNCurses::popup_clear_impl(void) { if (!popup.window) return; @@ -476,7 +475,7 @@ event_loop_iter() } void -InterfaceNCurses::event_loop(void) +InterfaceNCurses::event_loop_impl(void) { /* initial refresh: window might have been changed in batch mode */ current_view->refresh(); diff --git a/src/interface-ncurses.h b/src/interface-ncurses.h index 647b1ef..0d13615 100644 --- a/src/interface-ncurses.h +++ b/src/interface-ncurses.h @@ -31,7 +31,7 @@ namespace SciTECO { -typedef class ViewNCurses : public View { +typedef class ViewNCurses : public View<ViewNCurses> { Scintilla *sci; public: @@ -50,14 +50,15 @@ public: return scintilla_get_window(sci); } + /* implementation of View::ssm() */ inline sptr_t - ssm(unsigned int iMessage, uptr_t wParam = 0, sptr_t lParam = 0) + ssm_impl(unsigned int iMessage, uptr_t wParam = 0, sptr_t lParam = 0) { return scintilla_send_message(sci, iMessage, wParam, lParam); } } ViewCurrent; -typedef class InterfaceNCurses : public Interface { +typedef class InterfaceNCurses : public Interface<InterfaceNCurses, ViewNCurses> { SCREEN *screen; FILE *screen_tty; @@ -90,42 +91,54 @@ public: current_view(NULL) {} ~InterfaceNCurses(); - void main(int &argc, char **&argv); + /* implementation of Interface::main() */ + void main_impl(int &argc, char **&argv); - void vmsg(MessageType type, const gchar *fmt, va_list ap); + /* implementation of Interface::vmsg() */ + void vmsg_impl(MessageType type, const gchar *fmt, va_list ap); + /* override of Interface::msg_clear() */ void msg_clear(void); - void show_view(View *view); - inline View * - get_current_view(void) + /* implementation of Interface::show_view() */ + void show_view_impl(ViewNCurses *view); + /* implementation of Interface::get_current_view() */ + inline ViewNCurses * + get_current_view_impl(void) { return current_view; } + /* implementation of Interface::ssm() */ inline sptr_t - ssm(unsigned int iMessage, uptr_t wParam = 0, sptr_t lParam = 0) + ssm_impl(unsigned int iMessage, uptr_t wParam = 0, sptr_t lParam = 0) { return current_view->ssm(iMessage, wParam, lParam); } + /* implementation of Interface::undo_ssm() */ inline void - undo_ssm(unsigned int iMessage, - uptr_t wParam = 0, sptr_t lParam = 0) + undo_ssm_impl(unsigned int iMessage, + uptr_t wParam = 0, sptr_t lParam = 0) { current_view->undo_ssm(iMessage, wParam, lParam); } - void info_update(QRegister *reg); - void info_update(Buffer *buffer); + /* implementation of Interface::info_update() */ + void info_update_impl(QRegister *reg); + void info_update_impl(Buffer *buffer); - void cmdline_update(const gchar *cmdline = NULL); + /* implementation of Interface::cmdline_update() */ + void cmdline_update_impl(const gchar *cmdline = NULL); - void popup_add(PopupEntryType type, - const gchar *name, bool highlight = false); - void popup_show(void); - void popup_clear(void); + /* implementation of Interface::popup_add() */ + void popup_add_impl(PopupEntryType type, + const gchar *name, bool highlight = false); + /* implementation of Interface::popup_show() */ + void popup_show_impl(void); + /* implementation of Interface::popup_clear() */ + void popup_clear_impl(void); - /* main entry point */ - void event_loop(void); + /* main entry point (implementation) */ + void event_loop_impl(void); private: void init_screen(void); diff --git a/src/interface.cpp b/src/interface.cpp index aecba4e..fcb1738 100644 --- a/src/interface.cpp +++ b/src/interface.cpp @@ -34,8 +34,9 @@ namespace SciTECO { +template <class ViewImpl> void -View::set_representations(void) +View<ViewImpl>::set_representations(void) { static const char *reps[] = { "^@", "^A", "^B", "^C", "^D", "^E", "^F", "^G", @@ -50,8 +51,9 @@ View::set_representations(void) } } +template <class ViewImpl> void -View::initialize(void) +View<ViewImpl>::initialize(void) { ssm(SCI_SETFOCUS, TRUE); @@ -70,8 +72,11 @@ View::initialize(void) ssm(SCI_STYLESETBACK, STYLE_LINENUMBER, 0x000000); } +template class View<ViewCurrent>; + +template <class InterfaceImpl, class ViewImpl> void -Interface::UndoTokenShowView::run(void) +Interface<InterfaceImpl, ViewImpl>::UndoTokenShowView::run(void) { /* * Implementing this here allows us to reference @@ -80,8 +85,17 @@ Interface::UndoTokenShowView::run(void) interface.show_view(view); } +template <class InterfaceImpl, class ViewImpl> +template <class Type> +void +Interface<InterfaceImpl, ViewImpl>::UndoTokenInfoUpdate<Type>::run(void) +{ + interface.info_update(obj); +} + +template <class InterfaceImpl, class ViewImpl> void -Interface::stdio_vmsg(MessageType type, const gchar *fmt, va_list ap) +Interface<InterfaceImpl, ViewImpl>::stdio_vmsg(MessageType type, const gchar *fmt, va_list ap) { gchar buf[255]; @@ -103,12 +117,15 @@ Interface::stdio_vmsg(MessageType type, const gchar *fmt, va_list ap) } } +template <class InterfaceImpl, class ViewImpl> void -Interface::process_notify(SCNotification *notify) +Interface<InterfaceImpl, ViewImpl>::process_notify(SCNotification *notify) { #ifdef DEBUG g_printf("SCINTILLA NOTIFY: code=%d\n", notify->nmhdr.code); #endif } +template class Interface<InterfaceCurrent, ViewCurrent>; + } /* namespace SciTECO */ diff --git a/src/interface.h b/src/interface.h index bba761d..09b3c9a 100644 --- a/src/interface.h +++ b/src/interface.h @@ -34,16 +34,45 @@ class QRegister; class Buffer; extern sig_atomic_t sigint_occurred; +/** + * Base class for all SciTECO views. This is a minimal + * abstraction where the implementor only has to provide + * a method for dispatching Scintilla messages. + * Everything else is handled by other SciTECO classes. + * + * This interface employs the Curiously Recurring Template + * Pattern (CRTP). To implement it, one must derive from + * View<DerivedClass>. The methods to implement actually + * have an "_impl" suffix so as to avoid infinite recursion + * if an implementation is missing. + * Externally however, the methods as given in this interface + * may be called. + * + * The CRTP has a runtime overhead at low optimization levels + * (additional non-inlined calls), but should provide a + * significant performance boost when inlining is enabled. + * + * Note that not all methods have to be defined in the + * class. Explicit template instantiation is used to outsource + * base-class implementations to interface.cpp. + */ +template <class ViewImpl> class View { + inline ViewImpl & + impl(void) + { + return *(ViewImpl *)this; + } + class UndoTokenMessage : public UndoToken { - View *view; + ViewImpl &view; unsigned int iMessage; uptr_t wParam; sptr_t lParam; public: - UndoTokenMessage(View *_view, unsigned int _iMessage, + UndoTokenMessage(ViewImpl &_view, unsigned int _iMessage, uptr_t _wParam = 0, sptr_t _lParam = 0) : UndoToken(), view(_view), iMessage(_iMessage), @@ -52,61 +81,71 @@ class View { void run(void) { - view->ssm(iMessage, wParam, lParam); + view.ssm(iMessage, wParam, lParam); } }; class UndoTokenSetRepresentations : public UndoToken { - View *view; + ViewImpl &view; public: - UndoTokenSetRepresentations(View *_view) + UndoTokenSetRepresentations(ViewImpl &_view) : view(_view) {} void run(void) { - view->set_representations(); + view.set_representations(); } }; public: - virtual ~View() {} + inline sptr_t + ssm(unsigned int iMessage, + uptr_t wParam = 0, sptr_t lParam = 0) + { + return impl().ssm_impl(iMessage, wParam, lParam); + } - virtual sptr_t ssm(unsigned int iMessage, - uptr_t wParam = 0, sptr_t lParam = 0) = 0; inline void undo_ssm(unsigned int iMessage, uptr_t wParam = 0, sptr_t lParam = 0) { - undo.push(new UndoTokenMessage(this, iMessage, wParam, lParam)); + undo.push(new UndoTokenMessage(impl(), iMessage, wParam, lParam)); } void set_representations(void); inline void undo_set_representations(void) { - undo.push(new UndoTokenSetRepresentations(this)); + undo.push(new UndoTokenSetRepresentations(impl())); } protected: void initialize(void); }; -/* - * Base class for all user interfaces - used mereley as a class interface. - * The actual instance of the interface has the platform-specific type - * (e.g. InterfaceGtk) since we would like to have the benefits of using - * classes but avoid the calling overhead when invoking virtual methods - * on Interface pointers. - * There's only one Interface* instance in the system. +/** + * Base class and interface of all SciTECO user interfaces + * (e.g. Curses or GTK+). + * + * This uses the same Curiously Recurring Template Pattern (CRTP) + * as the View interface above, as there is only one type of + * user interface at runtime. */ +template <class InterfaceImpl, class ViewImpl> class Interface { + inline InterfaceImpl & + impl(void) + { + return *(InterfaceImpl *)this; + } + class UndoTokenShowView : public UndoToken { - View *view; + ViewImpl *view; public: - UndoTokenShowView(View *_view) + UndoTokenShowView(ViewImpl *_view) : view(_view) {} void run(void); @@ -120,23 +159,23 @@ class Interface { UndoTokenInfoUpdate(Type *_obj) : obj(_obj) {} - /* - * Implemented at bottom, so we can reference - * the singleton interface object. - * Alternative would be to do an extern explicit - * template instantiation. - */ void run(void); }; public: - virtual GOptionGroup * + /* default implementation */ + inline GOptionGroup * get_options(void) { return NULL; } + /* expected to initialize Scintilla */ - virtual void main(int &argc, char **&argv) = 0; + inline void + main(int &argc, char **&argv) + { + impl().main_impl(argc, argv); + } enum MessageType { MSG_USER, @@ -144,7 +183,11 @@ public: MSG_WARNING, MSG_ERROR }; - virtual void vmsg(MessageType type, const gchar *fmt, va_list ap) = 0; + inline void + vmsg(MessageType type, const gchar *fmt, va_list ap) + { + impl().vmsg_impl(type, fmt, ap); + } inline void msg(MessageType type, const gchar *fmt, ...) G_GNUC_PRINTF(3, 4) { @@ -154,56 +197,110 @@ public: vmsg(type, fmt, ap); va_end(ap); } - virtual void msg_clear(void) {} + /* default implementation */ + inline void msg_clear(void) {} - virtual void show_view(View *view) = 0; inline void - undo_show_view(View *view) + show_view(ViewImpl *view) + { + impl().show_view_impl(view); + } + inline void + undo_show_view(ViewImpl *view) { undo.push(new UndoTokenShowView(view)); } - virtual View *get_current_view(void) = 0; + inline ViewImpl * + get_current_view(void) + { + return impl().get_current_view_impl(); + } - virtual sptr_t ssm(unsigned int iMessage, - uptr_t wParam = 0, sptr_t lParam = 0) = 0; - virtual void undo_ssm(unsigned int iMessage, - uptr_t wParam = 0, sptr_t lParam = 0) = 0; + inline sptr_t + ssm(unsigned int iMessage, + uptr_t wParam = 0, sptr_t lParam = 0) + { + return impl().ssm_impl(iMessage, wParam, lParam); + } + inline void + undo_ssm(unsigned int iMessage, + uptr_t wParam = 0, sptr_t lParam = 0) + { + impl().undo_ssm_impl(iMessage, wParam, lParam); + } - virtual void info_update(QRegister *reg) = 0; - virtual void info_update(Buffer *buffer) = 0; + /* + * NOTE: could be rolled into a template, but + * this way it is explicit what must be implemented + * by the deriving class. + */ + inline void + info_update(QRegister *reg) + { + impl().info_update_impl(reg); + } + inline void + info_update(Buffer *buffer) + { + impl().info_update_impl(buffer); + } - template <class Type> inline void - undo_info_update(Type *obj) + undo_info_update(QRegister *reg) { - undo.push(new UndoTokenInfoUpdate<Type>(obj)); + undo.push(new UndoTokenInfoUpdate<QRegister>(reg)); + } + inline void + undo_info_update(Buffer *buffer) + { + undo.push(new UndoTokenInfoUpdate<Buffer>(buffer)); } /* NULL means to redraw the current cmdline if necessary */ - virtual void cmdline_update(const gchar *cmdline = NULL) = 0; + inline void + cmdline_update(const gchar *cmdline = NULL) + { + impl().cmdline_update_impl(cmdline); + } enum PopupEntryType { POPUP_PLAIN, POPUP_FILE, POPUP_DIRECTORY }; - virtual void popup_add(PopupEntryType type, - const gchar *name, bool highlight = false) = 0; - virtual void popup_show(void) = 0; - virtual void popup_clear(void) = 0; + inline void + popup_add(PopupEntryType type, + const gchar *name, bool highlight = false) + { + impl().popup_add_impl(type, name, highlight); + } + inline void + popup_show(void) + { + impl().popup_show_impl(); + } + inline void + popup_clear(void) + { + impl().popup_clear_impl(); + } - virtual inline bool + /* default implementation */ + inline bool is_interrupted(void) { return sigint_occurred != FALSE; } /* main entry point */ - virtual void event_loop(void) = 0; + inline void + event_loop(void) + { + impl().event_loop_impl(); + } /* * Interfacing to the external SciTECO world - * See main.cpp */ protected: void stdio_vmsg(MessageType type, const gchar *fmt, va_list ap); @@ -226,12 +323,8 @@ namespace SciTECO { /* object defined in main.cpp */ extern InterfaceCurrent interface; -template <class Type> -void -Interface::UndoTokenInfoUpdate<Type>::run(void) -{ - interface.info_update(obj); -} +extern template class View<ViewCurrent>; +extern template class Interface<InterfaceCurrent, ViewCurrent>; } /* namespace SciTECO */ diff --git a/src/parser.cpp b/src/parser.cpp index 61d43cc..a510ab5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1277,7 +1277,8 @@ StateStart::custom(gchar chr) */ case '=': BEGIN_EXEC(this); - interface.msg(Interface::MSG_USER, "%" TECO_INTEGER_FORMAT, + interface.msg(InterfaceCurrent::MSG_USER, + "%" TECO_INTEGER_FORMAT, expressions.pop_num_calc()); break; diff --git a/src/ring.cpp b/src/ring.cpp index 25a46ce..443b22d 100644 --- a/src/ring.cpp +++ b/src/ring.cpp @@ -264,18 +264,18 @@ Ring::edit(const gchar *filename) buffer->edit(); buffer->load(filename); - interface.msg(Interface::MSG_INFO, + interface.msg(InterfaceCurrent::MSG_INFO, "Added file \"%s\" to ring", filename); } else { buffer->edit(); buffer->set_filename(filename); if (filename) - interface.msg(Interface::MSG_INFO, + interface.msg(InterfaceCurrent::MSG_INFO, "Added new file \"%s\" to ring", filename); else - interface.msg(Interface::MSG_INFO, + interface.msg(InterfaceCurrent::MSG_INFO, "Added new unnamed file to ring."); } @@ -326,7 +326,7 @@ public: orig_attrs); #endif } else { - interface.msg(Interface::MSG_WARNING, + interface.msg(InterfaceCurrent::MSG_WARNING, "Unable to restore save point file \"%s\"", savepoint); } @@ -362,7 +362,7 @@ make_savepoint(Buffer *buffer) #endif undo.push(token); } else { - interface.msg(Interface::MSG_WARNING, + interface.msg(InterfaceCurrent::MSG_WARNING, "Unable to create save point file \"%s\"", savepoint); g_free(savepoint); @@ -475,11 +475,11 @@ Ring::close(Buffer *buffer) TAILQ_REMOVE(&head, buffer, buffers); if (buffer->filename) - interface.msg(Interface::MSG_INFO, + interface.msg(InterfaceCurrent::MSG_INFO, "Removed file \"%s\" from the ring", buffer->filename); else - interface.msg(Interface::MSG_INFO, + interface.msg(InterfaceCurrent::MSG_INFO, "Removed unnamed file from the ring."); } @@ -644,7 +644,7 @@ StateEditFile::initial(void) if (id == 0) { for (Buffer *cur = ring.first(); cur; cur = cur->next()) - interface.popup_add(Interface::POPUP_FILE, + interface.popup_add(InterfaceCurrent::POPUP_FILE, cur->filename ? : "(Unnamed)", cur == ring.current); diff --git a/src/search.cpp b/src/search.cpp index 16706ee..77a563a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -526,7 +526,7 @@ StateSearch::done(const gchar *str) expressions.push(search_reg->get_integer()); else if (IS_FAILURE(search_reg->get_integer()) && !expressions.find_op(Expressions::OP_LOOP) /* not in loop */) - interface.msg(Interface::MSG_ERROR, "Search string not found!"); + interface.msg(InterfaceCurrent::MSG_ERROR, "Search string not found!"); return &States::start; } |