"Fossies" - the Fresh Open Source Software Archive

Member "fityk-1.3.1/wxgui/editor.cpp" (13 May 2016, 16568 Bytes) of package /linux/misc/fityk-1.3.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "editor.cpp" see the Fossies "Dox" file reference documentation.

    1 // This file is part of fityk program. Copyright 2001-2013 Marcin Wojdyr
    2 // Licence: GNU General Public License ver. 2+
    3 
    4 ///  Script Editor and Debugger (EditorDlg)
    5 
    6 #include <wx/wx.h>
    7 
    8 #include "editor.h"
    9 #include "frame.h" //ftk, exec()
   10 #include "fityk/logic.h"
   11 #include "fityk/luabridge.h"
   12 
   13 #include "img/exec_selected.xpm"
   14 #include "img/exec_down.xpm"
   15 #include "img/save.xpm"
   16 #include "img/save_as.xpm"
   17 #include "img/close.xpm"
   18 
   19 #include <wx/stc/stc.h>
   20 #ifdef __WXOSX_CARBON__
   21 #include <wx/generic/buttonbar.h>
   22 #define wxToolBar wxButtonToolBar
   23 #endif
   24 
   25 using namespace std;
   26 
   27 
   28 enum {
   29     ID_SE_EXEC           = 28300,
   30     ID_SE_STEP                  ,
   31     ID_SE_SAVE                  ,
   32     ID_SE_SAVE_AS               ,
   33     ID_SE_CLOSE                 ,
   34     ID_SE_EDITOR
   35 };
   36 
   37 
   38 BEGIN_EVENT_TABLE(EditorDlg, wxDialog)
   39     EVT_TOOL(ID_SE_EXEC, EditorDlg::OnExec)
   40     EVT_TOOL(ID_SE_STEP, EditorDlg::OnStep)
   41     EVT_TOOL(ID_SE_SAVE, EditorDlg::OnSave)
   42     EVT_TOOL(ID_SE_SAVE_AS, EditorDlg::OnSaveAs)
   43     EVT_TOOL(ID_SE_CLOSE, EditorDlg::OnButtonClose)
   44 #if wxUSE_STC
   45     EVT_STC_CHANGE(ID_SE_EDITOR, EditorDlg::OnTextChange)
   46 #endif
   47     EVT_CLOSE(EditorDlg::OnCloseDlg)
   48 END_EVENT_TABLE()
   49 
   50 
   51 // compare with
   52 // http://sourceforge.net/p/scintilla/scite/ci/default/tree/src/lua.properties
   53 // http://git.geany.org/geany/tree/data/filetypes.lua
   54 static const char* kLuaMostOfKeywords =
   55 "and break do else elseif end for function goto if in local not"
   56 " or repeat return then until while";
   57 
   58 static const char* kLuaValueKeywords = "false nil true";
   59 
   60 // constants and functions
   61 static const char* kLuaFunctions =
   62 "_G _VERSION _ENV "
   63 " assert collectgarbage dofile error getmetatable ipairs load loadfile"
   64 " next pairs pcall print rawequal rawget rawlen rawset require"
   65 " select setmetatable tonumber tostring type xpcall"
   66 " bit32.arshift bit32.band bit32.bnot bit32.bor bit32.btest bit32.bxor"
   67 " bit32.extract bit32.lrotate bit32.lshift bit32.replace bit32.rrotate"
   68 " bit32.rshift"
   69 " coroutine.create coroutine.resume coroutine.running"
   70 " coroutine.status coroutine.wrap coroutine.yield"
   71 " debug.debug debug.getfenv debug.gethook debug.getinfo debug.getlocal"
   72 " debug.getmetatable debug.getregistry debug.getupvalue"
   73 " debug.getuservalue debug.setfenv debug.sethook debug.setlocal"
   74 " debug.setmetatable debug.setupvalue debug.setuservalue debug.traceback"
   75 " debug.upvalueid debug.upvaluejoin "
   76 " io.close io.flush io.input io.lines io.open io.output io.popen io.read"
   77 " io.stderr io.stdin io.stdout io.tmpfile io.type io.write"
   78 " math.abs math.acos math.asin math.atan math.atan2 math.ceil math.cos"
   79 " math.cosh math.deg math.exp math.floor math.fmod math.frexp math.huge"
   80 " math.ldexp math.log math.log10 math.max math.min math.modf math.pi"
   81 " math.pow math.rad math.random math.randomseed math.sin math.sinh"
   82 " math.sqrt math.tan math.tanh"
   83 " os.clock os.date os.difftime os.execute os.exit os.getenv os.remove"
   84 " os.rename os.setlocale os.time os.tmpname"
   85 " package.config package.cpath package.loaded package.loadlib package.path"
   86 " package.preload package.searchers package.searchpath"
   87 " string.byte string.char string.dump string.find"
   88 " string.format string.gmatch string.gsub string.len string.lower"
   89 " string.match string.rep string.reverse string.sub string.upper"
   90 " table.concat table.insert table.maxn table.pack table.remove"
   91 " table.sort table.unpack";
   92 
   93 static const char* kLuaMethods =
   94 "close flush lines read seek setvbuf write"
   95 " byte find format gmatch gsub len lower match rep reverse sub upper";
   96 
   97 static const char* kLuaTableF =
   98 "F:add_point F:all_functions F:all_parameters F:all_variables"
   99 " F:calculate_expr F:execute F:get_components"
  100 " F:get_covariance_matrix F:get_data F:get_dataset_count"
  101 " F:get_default_dataset F:get_dof F:get_function F:get_info"
  102 " F:get_model_value F:get_option_as_number F:get_option_as_string"
  103 " F:get_parameter_count F:get_rsquared F:get_ssr F:get_variable"
  104 " F:get_view_boundary F:get_wssr F:input F:load_data F:out"
  105 " F:set_option_as_number F:set_option_as_string";
  106 
  107 #if wxUSE_STC
  108 class FitykEditor : public wxStyledTextCtrl
  109 {
  110 public:
  111     FitykEditor(wxWindow* parent, wxWindowID id)
  112         : wxStyledTextCtrl(parent, id)
  113     {
  114         SetMarginType(0, wxSTC_MARGIN_NUMBER);
  115         SetMarginWidth(0, 32);
  116         SetUseVerticalScrollBar(true);
  117 #ifdef __WXMAC__
  118         const int font_size = 13;
  119 #else
  120         const int font_size = 11;
  121 #endif
  122         wxFont mono(wxFontInfo(font_size).Family(wxFONTFAMILY_TELETYPE));
  123         StyleSetFont(wxSTC_STYLE_DEFAULT, mono);
  124         SetIndent(2);
  125         SetUseTabs(false);
  126         SetTabIndents(true);
  127         SetBackSpaceUnIndents(true);
  128         AutoCompSetAutoHide(false);
  129         AutoCompSetCancelAtStart(false);
  130         SetIndentationGuides(3 /*SC_IV_LOOKBOTH*/);
  131         wxFont bold(StyleGetFont(wxSTC_STYLE_DEFAULT).Bold());
  132         StyleSetFont(wxSTC_STYLE_BRACELIGHT, bold);
  133         StyleSetForeground(wxSTC_STYLE_BRACELIGHT, wxColour(0, 0, 255));
  134         StyleSetFont(wxSTC_STYLE_BRACEBAD, bold);
  135         StyleSetForeground(wxSTC_STYLE_BRACEBAD, wxColour(144, 0, 0));
  136         Connect(wxID_ANY, wxEVT_STC_CHARADDED,
  137                 wxStyledTextEventHandler(FitykEditor::OnCharAdded));
  138         Connect(wxID_ANY, wxEVT_STC_UPDATEUI,
  139                 wxStyledTextEventHandler(FitykEditor::OnUpdateUI));
  140     }
  141 
  142     void set_filetype(bool lua)
  143     {
  144         wxColour comment_col(10, 150, 10);
  145         if (lua) {
  146             // use similar colors as in Lua wiki
  147             SetLexer(wxSTC_LEX_LUA);
  148             //SetProperty("fold", "1");
  149             StyleSetForeground(wxSTC_LUA_COMMENT, comment_col);
  150             StyleSetForeground(wxSTC_LUA_COMMENTLINE, comment_col);
  151             StyleSetForeground(wxSTC_LUA_COMMENTDOC, comment_col);
  152             wxColour string_col(0, 144, 144);
  153             StyleSetForeground(wxSTC_LUA_STRING, string_col);
  154             StyleSetForeground(wxSTC_LUA_CHARACTER, string_col);
  155             StyleSetForeground(wxSTC_LUA_LITERALSTRING, string_col);
  156             StyleSetForeground(wxSTC_LUA_NUMBER, wxColour(32, 80, 96));
  157             SetKeyWords(0, kLuaMostOfKeywords);
  158             wxFont bold(StyleGetFont(wxSTC_STYLE_DEFAULT).Bold());
  159             StyleSetFont(wxSTC_LUA_WORD, bold);
  160             StyleSetForeground(wxSTC_LUA_WORD, wxColour(0, 0, 128));
  161             SetKeyWords(1, kLuaValueKeywords);
  162             StyleSetForeground(wxSTC_LUA_WORD2, wxColour(0, 0, 128));
  163             SetKeyWords(2, kLuaFunctions);
  164             StyleSetForeground(wxSTC_LUA_WORD3, wxColour(144, 0, 144));
  165             SetKeyWords(3, kLuaMethods);
  166             StyleSetForeground(wxSTC_LUA_WORD4, wxColour(144, 0, 144));
  167             SetKeyWords(4, "F");
  168             StyleSetFont(wxSTC_LUA_WORD5, bold);
  169         } else {
  170             // actually we set filetype to apache config, but since
  171             // we only customize colors of comments it works fine.
  172             SetLexer(wxSTC_LEX_CONF);
  173             StyleSetForeground(wxSTC_CONF_COMMENT, comment_col);
  174         }
  175     }
  176 
  177     void OnCharAdded(wxStyledTextEvent& event)
  178     {
  179         // auto-indentation (the same as previous line)
  180         if (event.GetKey() == '\n') {
  181             int line = GetCurrentLine();
  182             if (line > 0) { // just in case
  183                 int indent = GetLineIndentation(line-1);
  184                 if (indent > 0) {
  185                     SetLineIndentation(line, indent);
  186                     LineEnd();
  187                 }
  188             }
  189         }
  190         // auto-completion
  191         if (GetLexer() == wxSTC_LEX_LUA && !AutoCompActive())
  192             LuaAutocomp();
  193     }
  194 
  195     void LuaAutocomp()
  196     {
  197         int pos = GetCurrentPos() - 1; // GetCurrentPos() returns
  198         if (pos < 1)
  199             return;
  200         char key = GetCharAt(pos);
  201         if (key == ':' && GetStyleAt(pos-1) == wxSTC_LUA_WORD5) {
  202             // wxSTC_LUA_WORD5 is only "F", so other checks are redundant:
  203             //      GetCharAt(pos-1) == 'F' &&
  204             //      WordStartPosition(pos-1, true) == pos-1)
  205             AutoCompShow(2, kLuaTableF);
  206         }
  207         else if (key == '.' && GetStyleAt(pos-1) == wxSTC_LUA_IDENTIFIER) {
  208             int start = WordStartPosition(pos-1, true);
  209             wxString word = GetTextRange(start, pos);
  210             if (word == "bit32" || word == "coroutine" || word == "debug" ||
  211                     word == "io" || word == "math" || word == "os" ||
  212                     word == "package" || word == "string" || word == "table") {
  213                 AutoCompShow(pos-start+1, kLuaFunctions);
  214             }
  215         }
  216     }
  217 
  218     void OnUpdateUI(wxStyledTextEvent&)
  219     {
  220         const char* braces = "(){}[]";
  221         int p = GetCurrentPos();
  222         int brace_pos = -1;
  223         if (p > 1 && strchr(braces, GetCharAt(p-1)))
  224             brace_pos = p - 1;
  225         else if (strchr(braces, GetCharAt(p)))
  226             brace_pos = p;
  227         if (brace_pos != -1) {
  228             int match_pos = BraceMatch(brace_pos);
  229             if (match_pos == wxSTC_INVALID_POSITION)
  230                 BraceBadLight(brace_pos);
  231             else
  232                 BraceHighlight(brace_pos, match_pos);
  233         } else {
  234             BraceBadLight(wxSTC_INVALID_POSITION); // remove brace light
  235         }
  236     }
  237 };
  238 
  239 #else
  240 class FitykEditor : public wxTextCtrl
  241 {
  242 public:
  243     FitykEditor(wxWindow* parent, wxWindowID id)
  244         : wxTextCtrl(parent, id, "", wxDefaultPosition, wxDefaultSize,
  245                      wxTE_MULTILINE|wxTE_RICH) {}
  246     void set_filetype(bool) {}
  247     int GetCurrentLine() const
  248             { long x, y; PositionToXY(GetInsertionPoint(), &x, &y); return y; }
  249     void GotoLine(int line) { SetInsertionPoint(ed_->XYToPosition(0, line)); }
  250 };
  251 #endif
  252 
  253 
  254 EditorDlg::EditorDlg(wxWindow* parent)
  255     : wxDialog(parent, -1, wxT(""),
  256                wxDefaultPosition, wxSize(600, 500),
  257                wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER),
  258       lua_file_(false)
  259 {
  260     wxBoxSizer *top_sizer = new wxBoxSizer(wxVERTICAL);
  261     tb_ = new wxToolBar(this, -1, wxDefaultPosition, wxDefaultSize,
  262                        wxTB_TEXT | wxTB_HORIZONTAL | wxNO_BORDER);
  263     tb_->SetToolBitmapSize(wxSize(24, 24));
  264     tb_->AddTool(ID_SE_EXEC, wxT("Execute"),
  265                  wxBitmap(exec_selected_xpm), wxNullBitmap,
  266                  wxITEM_NORMAL,
  267                  wxT("Execute all or selected lines"));
  268     tb_->AddTool(ID_SE_STEP, wxT("Step"),
  269                  wxBitmap(exec_down_xpm), wxNullBitmap,
  270                  wxITEM_NORMAL,
  271                  wxT("Execute line and go to the next line"));
  272     tb_->AddSeparator();
  273     tb_->AddTool(ID_SE_SAVE, wxT("Save"), wxBitmap(save_xpm), wxNullBitmap,
  274                  wxITEM_NORMAL,
  275                  wxT("Save to file"));
  276     tb_->AddTool(ID_SE_SAVE_AS, wxT("Save as"),
  277                  wxBitmap(save_as_xpm), wxNullBitmap,
  278                  wxITEM_NORMAL,
  279                  wxT("Save a copy to file"));
  280 #if 0
  281     tb_->AddSeparator();
  282     tb_->AddTool(wxID_UNDO, wxT("Undo"),
  283                  wxBitmap(undo_xpm), wxNullBitmap,
  284                  wxITEM_NORMAL, wxT("Undo"),
  285                  wxT("Undo the last edit"));
  286     tb_->AddTool(wxID_REDO, wxT("Redo"),
  287                  wxBitmap(redo_xpm), wxNullBitmap,
  288                  wxITEM_NORMAL, wxT("Redo"),
  289                  wxT("Redo the last undone edit"));
  290 #endif
  291     tb_->AddSeparator();
  292     tb_->AddTool(ID_SE_CLOSE, wxT("Close"), wxBitmap(close_xpm), wxNullBitmap,
  293                  wxITEM_NORMAL, wxT("Exit debugger"), wxT("Close debugger"));
  294 #ifdef __WXOSX_CARBON__
  295     for (size_t i = 0; i < tb_->GetToolsCount(); ++i) {
  296         const wxToolBarToolBase *tool = tb_->GetToolByPos(i);
  297         tb_->SetToolShortHelp(tool->GetId(), tool->GetLabel());
  298     }
  299 #endif
  300     tb_->Realize();
  301     top_sizer->Add(tb_, 0, wxEXPAND);
  302     ed_ = new FitykEditor(this, ID_SE_EDITOR);
  303     top_sizer->Add(ed_, 1, wxALL|wxEXPAND, 0);
  304     SetSizerAndFit(top_sizer);
  305     SetSize(600, 500);
  306 }
  307 
  308 void EditorDlg::open_file(const wxString& path)
  309 {
  310     if (wxFileExists(path))
  311         ed_->LoadFile(path);
  312     else
  313         ed_->Clear();
  314     path_ = path;
  315     lua_file_ = path.Lower().EndsWith("lua");
  316     ed_->set_filetype(lua_file_);
  317 #if wxUSE_STC
  318     // i don't know why, but in wxGTK 2.9.3 initially all text is selected
  319     ed_->ClearSelections();
  320 #endif
  321     ed_->DiscardEdits();
  322     update_title();
  323 }
  324 
  325 void EditorDlg::new_file_with_content(const wxString& content)
  326 {
  327     ed_->ChangeValue(content);
  328     path_.clear();
  329     lua_file_ = content.StartsWith("--");
  330     ed_->set_filetype(lua_file_);
  331 #if wxUSE_STC
  332     // i don't know why, but in wxGTK 2.9.3 initially all text is selected
  333     ed_->ClearSelections();
  334     ed_->GotoLine(ed_->GetLineCount() - 1);
  335 #else
  336     ed_->SetInsertionPointEnd();
  337 #endif
  338     ed_->DiscardEdits();
  339     update_title();
  340 }
  341 
  342 void EditorDlg::on_save()
  343 {
  344     if (!path_.empty())
  345         do_save_file(path_);
  346     else
  347         on_save_as();
  348 }
  349 
  350 void EditorDlg::on_save_as()
  351 {
  352     wxFileDialog dialog(this, "save script as...", frame->script_dir(), "",
  353                         "Fityk scripts (*.fit)|*.fit;*.FIT"
  354                         "|Lua scripts (*.lua)|*.lua;*.LUA"
  355                         "|all files|*",
  356                         wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
  357     if (lua_file_)
  358         dialog.SetFilterIndex(1);
  359     if (dialog.ShowModal() == wxID_OK) {
  360         do_save_file(dialog.GetPath());
  361         frame->set_script_dir(dialog.GetDirectory());
  362     }
  363 }
  364 
  365 void EditorDlg::do_save_file(const wxString& save_path)
  366 {
  367     bool r = ed_->SaveFile(save_path);
  368     if (r) {
  369         path_ = save_path;
  370         ed_->DiscardEdits();
  371         update_title();
  372     }
  373 }
  374 
  375 string EditorDlg::get_editor_line(int n)
  376 {
  377     string line = wx2s(ed_->GetLineText(n));
  378     if (!line.empty() && *(line.end()-1) == '\n') {
  379         line.resize(line.size() - 1);
  380         if (!line.empty() && *(line.end()-1) == '\r')
  381             line.resize(line.size() - 1);
  382     }
  383     return line;
  384 }
  385 
  386 int EditorDlg::exec_fityk_line(int n)
  387 {
  388     if (n < 0)
  389         return 1;
  390     string s = get_editor_line(n);
  391     int counter = 1;
  392     while (!s.empty() && *(s.end()-1) == '\\') {
  393         s.resize(s.size() - 1);
  394         s += get_editor_line(n+counter);
  395         ++counter;
  396     }
  397 
  398     // the same replacement as in UserInterface::exec_script()
  399     if (s.find("_SCRIPT_DIR_/") != string::npos) {
  400         string dir = fityk::get_directory(wx2s(path_));
  401         fityk::replace_all(s, "_EXECUTED_SCRIPT_DIR_/", dir);// old magic string
  402         fityk::replace_all(s, "_SCRIPT_DIR_/", dir); // new magic string
  403     }
  404 
  405     exec(s);
  406     /*
  407     UserInterface::Status r = exec(s);
  408     if (r == UserInterface::kStatusOk) {
  409     } else { // error
  410     }
  411     */
  412     return counter;
  413 }
  414 
  415 int EditorDlg::exec_lua_line(int n)
  416 {
  417     if (n < 0)
  418         return 1;
  419     string s = get_editor_line(n);
  420     int counter = 1;
  421     if (s.empty())
  422         return counter;
  423     while (ftk->lua_bridge()->is_lua_line_incomplete(s.c_str())) {
  424         if (n+counter >= ed_->GetLineCount())
  425             break;
  426         s += "\n    " + get_editor_line(n+counter);
  427         ++counter;
  428     }
  429 
  430     exec("lua " + s);
  431     /*
  432     UserInterface::Status r = exec(s);
  433     if (r == UserInterface::kStatusOk) {
  434     } else { // error
  435     }
  436     */
  437     return counter;
  438 }
  439 
  440 void EditorDlg::OnExec(wxCommandEvent&)
  441 {
  442     long p1, p2;
  443     ed_->GetSelection(&p1, &p2);
  444     long y1=0, y2=0;
  445     if (p1 != p2) { //selection, exec whole lines
  446         long x;
  447         ed_->PositionToXY(p1, &x, &y1);
  448         ed_->PositionToXY(p2, &x, &y2);
  449     } else
  450         y2 = ed_->GetNumberOfLines();
  451 
  452     for (int i = y1; i <= y2; )
  453         i += lua_file_ ? exec_lua_line(i) : exec_fityk_line(i);
  454 }
  455 
  456 void EditorDlg::OnStep(wxCommandEvent&)
  457 {
  458     int y  = ed_->GetCurrentLine();
  459     int n = lua_file_ ? exec_lua_line(y) : exec_fityk_line(y);
  460     ed_->GotoLine(y+n);
  461 }
  462 
  463 void EditorDlg::OnTextChange(wxStyledTextEvent&)
  464 {
  465     if (GetTitle().EndsWith(wxT(" *")) != ed_->IsModified())
  466         update_title();
  467 #if 0
  468     tb_->EnableTool(wxID_UNDO, ed_->CanUndo());
  469     tb_->EnableTool(wxID_REDO, ed_->CanRedo());
  470 #endif
  471 }
  472 
  473 void EditorDlg::update_title()
  474 {
  475     wxString p = path_.empty() ? wxString(wxT("unnamed")) : path_;
  476     if (ed_->IsModified())
  477         p += wxT(" *");
  478     SetTitle(p);
  479     tb_->EnableTool(ID_SE_SAVE, !path_.empty() && ed_->IsModified());
  480 }
  481 
  482 void EditorDlg::OnCloseDlg(wxCloseEvent& event)
  483 {
  484     if (ed_->IsModified()) {
  485         int r = wxMessageBox("Save before closing?", "Save?",
  486                              wxYES_NO | wxCANCEL | wxICON_QUESTION);
  487         if (r == wxCANCEL) {
  488             event.Veto();
  489             return;
  490         }
  491         if (r == wxYES)
  492             on_save();
  493     }
  494     Destroy();
  495 }
  496