From 7986220a0ec90939eeded3312042862b5048cd7c Mon Sep 17 00:00:00 2001 From: Hans-Albert Maritz Date: Sat, 28 Feb 2015 16:01:47 +1100 Subject: [PATCH 1/9] Started work on search function and refactoring of output panel --- src/dlangide/ui/frame.d | 5 +++ src/dlangide/ui/outputpanel.d | 37 ++++++++++++++++---- src/dlangide/ui/searchPanel.d | 66 +++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 src/dlangide/ui/searchPanel.d diff --git a/src/dlangide/ui/frame.d b/src/dlangide/ui/frame.d index 67ea836..0168dd9 100644 --- a/src/dlangide/ui/frame.d +++ b/src/dlangide/ui/frame.d @@ -341,6 +341,11 @@ class IDEFrame : AppFrame { _logPanel.appendText(null, "cannot start dcd-server: code completion for D code will not work"d); } + import dlangide.ui.searchPanel; + auto searchPanel = new SearchWidget("search", this); + + _logPanel.getTabs.addTab( searchPanel, "Search"d, null, true); + _dockHost.addDockedWindow(_logPanel); return _dockHost; diff --git a/src/dlangide/ui/outputpanel.d b/src/dlangide/ui/outputpanel.d index f997429..5f1efa0 100644 --- a/src/dlangide/ui/outputpanel.d +++ b/src/dlangide/ui/outputpanel.d @@ -3,16 +3,19 @@ module dlangide.ui.outputpanel; import dlangui; import dlangide.workspace.workspace; import dlangide.workspace.project; +import dlangide.ui.frame; import std.utf; import std.regex; import std.algorithm : startsWith; +import std.string; /// event listener to navigate by error/warning position interface CompilerLogIssueClickHandler { bool onCompilerLogIssueClick(dstring filename, int line, int column); } + /// Log widget with parsing of compiler output class CompilerLogWidget : LogWidget { @@ -113,20 +116,42 @@ class OutputPanel : DockWindow { protected CompilerLogWidget _logWidget; + TabWidget _tabs; + + @property TabWidget getTabs() { return _tabs;} + this(string id) { + _showCloseButton = false; + dockAlignment = DockAlignment.Bottom; super(id); - _caption.text = "Output"d; - dockAlignment = DockAlignment.Bottom; - } + + } override protected Widget createBodyWidget() { + _tabs = new TabWidget("OutputPanelTabs"); + _tabs.setStyles(STYLE_DOCK_HOST_BODY, STYLE_TAB_UP_DARK, STYLE_TAB_UP_BUTTON_DARK, STYLE_TAB_UP_BUTTON_DARK_TEXT); + _logWidget = new CompilerLogWidget("logwidget"); _logWidget.readOnly = true; - _logWidget.layoutHeight(FILL_PARENT).layoutHeight(FILL_PARENT); + _logWidget.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); _logWidget.compilerLogIssueClickHandler = &onIssueClick; - return _logWidget; + + _tabs.addTab(_logWidget, "Compiler Log"d); + _tabs.selectTab("logwidget"); + + return _tabs; } + override protected void init() { + + styleId = STYLE_DOCK_WINDOW; + _bodyWidget = createBodyWidget(); + _bodyWidget.styleId = STYLE_DOCK_WINDOW_BODY; + addChild(_bodyWidget); + } + + //TODO: Refactor OutputPanel to expose CompilerLogWidget + void appendText(string category, dstring msg) { _logWidget.appendText(msg); } @@ -159,4 +184,4 @@ class OutputPanel : DockWindow { return true; } -} +} \ No newline at end of file diff --git a/src/dlangide/ui/searchPanel.d b/src/dlangide/ui/searchPanel.d new file mode 100644 index 0000000..3b61abb --- /dev/null +++ b/src/dlangide/ui/searchPanel.d @@ -0,0 +1,66 @@ +module dlangide.ui.searchPanel; + +import dlangide.ui.frame; +import dlangui; + +class SearchWidget : TabWidget { + HorizontalLayout _layout; + EditLine _findText; + LogWidget _resultLog; + + + protected IDEFrame _frame; + + this(string ID, IDEFrame frame) { + super(ID); + _frame = frame; + + //Remove title, more button + removeAllChildren(); + + _layout = new HorizontalLayout(); + _layout.addChild(new TextWidget("FindLabel", "Find: "d)); + + _findText = new EditLine(); + _findText.padding(Rect(5,4,50,4)); + _findText.layoutWidth(400); + _layout.addChild(_findText); + + auto goButton = new ImageButton("findTextButton", "edit-redo"); + goButton.addOnClickListener( delegate(Widget) { + findText(_findText.text); + return true; + }); + _layout.addChild(goButton); + addChild(_layout); + + _resultLog = new LogWidget("SearchLogWidget"); + _resultLog.layoutHeight(FILL_PARENT); + addChild(_resultLog); + + } + + bool findText(dstring source) { + struct SearchMatch { + int line; + long col; + string fileName; + } + + import std.string; + SearchMatch[] matches; + //TODO Should not crash when in homepage. + foreach(int lineIndex, dstring line; _frame.currentEditor.content.lines) { + auto colIndex = line.indexOf(source); + if( colIndex != -1) { + matches ~= SearchMatch(lineIndex+1, colIndex, ""); + _resultLog.appendText( " " ~ to!dstring(matches[$-1]) ~ '\n'); + } + } +// _resultLog.text = ""; +// if(matches.length > 1){ +// _resultLog.appendText(to!dstring(matches[0].line)); +// } + return false; + } +} \ No newline at end of file From ca2bca72ed9a608d04a1629361b40ece7a16e5bd Mon Sep 17 00:00:00 2001 From: Hans-Albert Maritz Date: Tue, 3 Mar 2015 00:44:15 +1100 Subject: [PATCH 2/9] Display whether matches were found or not --- src/dlangide/ui/searchPanel.d | 37 ++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/dlangide/ui/searchPanel.d b/src/dlangide/ui/searchPanel.d index 3b61abb..dc4072e 100644 --- a/src/dlangide/ui/searchPanel.d +++ b/src/dlangide/ui/searchPanel.d @@ -3,13 +3,25 @@ import dlangide.ui.frame; import dlangui; +import std.string; +import std.conv; + class SearchWidget : TabWidget { HorizontalLayout _layout; EditLine _findText; LogWidget _resultLog; - protected IDEFrame _frame; + + struct SearchMatch { + int line; + long col; + string fileName; + + string toString() { + return to!string(line) ~ ':' ~ to!string(col) ~ ' ' ~ fileName; + } + } this(string ID, IDEFrame frame) { super(ID); @@ -41,26 +53,23 @@ class SearchWidget : TabWidget { } bool findText(dstring source) { - struct SearchMatch { - int line; - long col; - string fileName; - } - - import std.string; SearchMatch[] matches; //TODO Should not crash when in homepage. foreach(int lineIndex, dstring line; _frame.currentEditor.content.lines) { auto colIndex = line.indexOf(source); if( colIndex != -1) { matches ~= SearchMatch(lineIndex+1, colIndex, ""); - _resultLog.appendText( " " ~ to!dstring(matches[$-1]) ~ '\n'); } } -// _resultLog.text = ""; -// if(matches.length > 1){ -// _resultLog.appendText(to!dstring(matches[0].line)); -// } - return false; + if(matches.length == 0) { + _resultLog.appendText(to!dstring("No matches in current file." ~ '\n')); + } + else { + _resultLog.appendText(to!dstring("Matches found in current file: " ~ '\n')); + foreach(SearchMatch match; matches) { + _resultLog.appendText(to!dstring(" ->" ~ match.toString ~ '\n')); + } + } + return true; } } \ No newline at end of file From 4178d63229e01dcb27bff331ff9ca9d3f9140f53 Mon Sep 17 00:00:00 2001 From: Hans-Albert Maritz Date: Sun, 8 Mar 2015 00:42:27 +1100 Subject: [PATCH 3/9] Search in other project items --- src/dlangide/ui/searchPanel.d | 61 +++++++++++++++++++++++++------- src/dlangide/workspace/project.d | 15 ++++++++ 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/dlangide/ui/searchPanel.d b/src/dlangide/ui/searchPanel.d index dc4072e..f8c9d28 100644 --- a/src/dlangide/ui/searchPanel.d +++ b/src/dlangide/ui/searchPanel.d @@ -1,7 +1,13 @@ module dlangide.ui.searchPanel; -import dlangide.ui.frame; + import dlangui; +import dlangui.core.editable; + +import dlangide.ui.frame; +import dlangide.ui.wspanel; +import dlangide.workspace.workspace; +import dlangide.workspace.project; import std.string; import std.conv; @@ -19,7 +25,7 @@ class SearchWidget : TabWidget { string fileName; string toString() { - return to!string(line) ~ ':' ~ to!string(col) ~ ' ' ~ fileName; + return '[' ~ to!string(line) ~ ':' ~ to!string(col) ~ "] " ~ fileName; } } @@ -48,28 +54,59 @@ class SearchWidget : TabWidget { _resultLog = new LogWidget("SearchLogWidget"); _resultLog.layoutHeight(FILL_PARENT); - addChild(_resultLog); + addChild(_resultLog); + } + + void searchInProject(ProjectItem project, ref SearchMatch[] matches, dstring text) { + if(project.isFolder) { + foreach(ProjectItem child; cast(ProjectFolder) project) { + searchInProject(child, matches, text); + } + } + else { + EditableContent content = new EditableContent(true); + content.load(project.filename); + foreach(int lineIndex, dstring line; content.lines) { + auto colIndex = line.indexOf(text); + if( colIndex != -1) { + matches ~= SearchMatch(lineIndex+1, colIndex, project.filename); + } + } + } + } bool findText(dstring source) { + Log.d("Finding " ~ source); SearchMatch[] matches; //TODO Should not crash when in homepage. - foreach(int lineIndex, dstring line; _frame.currentEditor.content.lines) { - auto colIndex = line.indexOf(source); - if( colIndex != -1) { - matches ~= SearchMatch(lineIndex+1, colIndex, ""); - } - } - if(matches.length == 0) { + + searchInProject(_frame.currentEditor.projectSourceFile, matches, source); + Log.d("Searching in current file " ~ source); + + if(currentWorkspace) { + foreach(ProjectItem project ; currentWorkspace.projects[0].items) { + searchInProject(project, matches, source); + } + } + + if(matches.length == 0) { _resultLog.appendText(to!dstring("No matches in current file." ~ '\n')); } else { _resultLog.appendText(to!dstring("Matches found in current file: " ~ '\n')); foreach(SearchMatch match; matches) { - _resultLog.appendText(to!dstring(" ->" ~ match.toString ~ '\n')); + if(match.fileName == _frame.currentEditor.content.filename) + _resultLog.appendText(to!dstring(" --> [" ~ to!string(match.line) ~ ':' ~ to!string(match.col) ~ "] in current file\n")); + else + _resultLog.appendText(to!dstring(" --> " ~ match.toString" ~ '\n')); } } + + + + return true; } -} \ No newline at end of file +} diff --git a/src/dlangide/workspace/project.d b/src/dlangide/workspace/project.d index 5dc712f..825ae76 100644 --- a/src/dlangide/workspace/project.d +++ b/src/dlangide/workspace/project.d @@ -135,6 +135,21 @@ class ProjectFolder : ProjectItem { return path; return buildNormalizedPath(_filename, path); } + + int begin; + int end; + bool empty() const { + return begin == _children.count; + } + + void popFront() + { + ++begin; + } + + ProjectItem front() { + return _children[begin]; + } } /// Project source file From d6cffd4e2e17f8ea812c69d8bd79a255c2140ba1 Mon Sep 17 00:00:00 2001 From: Hans-Albert Maritz Date: Sun, 8 Mar 2015 02:27:47 +1100 Subject: [PATCH 4/9] Added syntax highlighting to search results --- src/dlangide/ui/searchPanel.d | 117 +++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 30 deletions(-) diff --git a/src/dlangide/ui/searchPanel.d b/src/dlangide/ui/searchPanel.d index f8c9d28..784f7d8 100644 --- a/src/dlangide/ui/searchPanel.d +++ b/src/dlangide/ui/searchPanel.d @@ -12,6 +12,65 @@ import dlangide.workspace.project; import std.string; import std.conv; +class SearchLogWidget : LogWidget { + + this(string ID){ + super(ID); + } + + override protected CustomCharProps[] handleCustomLineHighlight(int line, dstring txt, ref CustomCharProps[] buf) { + uint defColor = textColor; + const uint filenameColor = 0x0000C0; + const uint errorColor = 0xFF0000; + const uint warningColor = 0x606000; + const uint deprecationColor = 0x802040; + uint flags = 0; + if (buf.length < txt.length) + buf.length = txt.length; + if(txt.startsWith("Matches in ")) { + CustomCharProps[] colors = buf[0..txt.length]; + uint cl = defColor; + flags = 0; + for (int i = 0; i < txt.length; i++) { + dstring rest = txt[i..$]; + if(i == 11) { + cl = filenameColor; + flags = TextFlag.Underline; + } + colors[i].color = cl; + colors[i].textFlags = flags; + } + return colors; + } + else { + CustomCharProps[] colors = buf[0..txt.length]; + uint cl = filenameColor; + flags = TextFlag.Underline; + for (int i = 0; i < txt.length; i++) { + dstring rest = txt[i..$]; + if (rest.startsWith(" -->"d)) { + cl = warningColor; + flags = 0; + } + if(i == 4) { + cl = errorColor; + flags = TextFlag.Underline; + } + + colors[i].color = cl; + colors[i].textFlags = flags; + + //Colors to applay after current character. + if(rest.startsWith("]")) { + cl = defColor; + flags = 0; + } + } + return colors; + } + } +} + class SearchWidget : TabWidget { HorizontalLayout _layout; EditLine _findText; @@ -22,12 +81,13 @@ class SearchWidget : TabWidget { struct SearchMatch { int line; long col; - string fileName; - - string toString() { - return '[' ~ to!string(line) ~ ':' ~ to!string(col) ~ "] " ~ fileName; - } + dstring lineContent; } + + struct SearchMatchList { + string filename; + SearchMatch[] matches; + } this(string ID, IDEFrame frame) { super(ID); @@ -52,61 +112,58 @@ class SearchWidget : TabWidget { _layout.addChild(goButton); addChild(_layout); - _resultLog = new LogWidget("SearchLogWidget"); + _resultLog = new SearchLogWidget("SearchLogWidget"); _resultLog.layoutHeight(FILL_PARENT); addChild(_resultLog); } - void searchInProject(ProjectItem project, ref SearchMatch[] matches, dstring text) { + void searchInProject(ProjectItem project, ref SearchMatchList[] matchList, dstring text) { if(project.isFolder) { foreach(ProjectItem child; cast(ProjectFolder) project) { - searchInProject(child, matches, text); + searchInProject(child, matchList, text); } } else { EditableContent content = new EditableContent(true); content.load(project.filename); + SearchMatchList match; + match.filename = project.filename; + foreach(int lineIndex, dstring line; content.lines) { auto colIndex = line.indexOf(text); if( colIndex != -1) { - matches ~= SearchMatch(lineIndex+1, colIndex, project.filename); + match.matches ~= SearchMatch(lineIndex+1, colIndex, line); } } - } + + if(match.matches.length > 0) { + matchList ~= match; + } + } } bool findText(dstring source) { Log.d("Finding " ~ source); - SearchMatch[] matches; + SearchMatchList[] matches; //TODO Should not crash when in homepage. - searchInProject(_frame.currentEditor.projectSourceFile, matches, source); - Log.d("Searching in current file " ~ source); - - if(currentWorkspace) { - foreach(ProjectItem project ; currentWorkspace.projects[0].items) { - searchInProject(project, matches, source); - } + foreach(Project project; _frame._wsPanel.workspace.projects) { + searchInProject(project.items, matches, source); } if(matches.length == 0) { - _resultLog.appendText(to!dstring("No matches in current file." ~ '\n')); + _resultLog.appendText(to!dstring("No matches found.\n")); } else { - _resultLog.appendText(to!dstring("Matches found in current file: " ~ '\n')); - foreach(SearchMatch match; matches) { - if(match.fileName == _frame.currentEditor.content.filename) - _resultLog.appendText(to!dstring(" --> [" ~ to!string(match.line) ~ ':' ~ to!string(match.col) ~ "] in current file\n")); - else - _resultLog.appendText(to!dstring(" --> " ~ match.toString" ~ '\n')); + foreach(SearchMatchList fileMatchList; matches) { + _resultLog.appendText("Matches in "d ~ to!dstring(fileMatchList.filename) ~ '\n'); + foreach(SearchMatch match; fileMatchList.matches) { + _resultLog.appendText(" --> ["d ~ to!dstring(match.line) ~ ":"d ~ to!dstring(match.col) ~ "]" ~ match.lineContent ~"\n"d); + } } } - - - - return true; } -} +} \ No newline at end of file From 19271b6233f50d1c125a53bcedb0ce1fb90cab7e Mon Sep 17 00:00:00 2001 From: Hans-Albert Maritz Date: Mon, 9 Mar 2015 01:11:39 +1100 Subject: [PATCH 5/9] Fixed display of SearchLogWidget when resizing, fixed doing multiple searches not working Also made the LogWidget not scroll to bottom. --- src/dlangide/ui/searchPanel.d | 24 ++++++++++++++++-------- src/dlangide/workspace/project.d | 19 ++----------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/dlangide/ui/searchPanel.d b/src/dlangide/ui/searchPanel.d index 784f7d8..15e3026 100644 --- a/src/dlangide/ui/searchPanel.d +++ b/src/dlangide/ui/searchPanel.d @@ -16,6 +16,8 @@ class SearchLogWidget : LogWidget { this(string ID){ super(ID); + scrollLock = false; + } override protected CustomCharProps[] handleCustomLineHighlight(int line, dstring txt, ref CustomCharProps[] buf) { @@ -92,7 +94,8 @@ class SearchWidget : TabWidget { this(string ID, IDEFrame frame) { super(ID); _frame = frame; - + layoutHeight(FILL_PARENT); + //Remove title, more button removeAllChildren(); @@ -115,17 +118,17 @@ class SearchWidget : TabWidget { _resultLog = new SearchLogWidget("SearchLogWidget"); _resultLog.layoutHeight(FILL_PARENT); addChild(_resultLog); - - } void searchInProject(ProjectItem project, ref SearchMatchList[] matchList, dstring text) { - if(project.isFolder) { - foreach(ProjectItem child; cast(ProjectFolder) project) { - searchInProject(child, matchList, text); - } + if(project.isFolder == true) { + ProjectFolder projFolder = cast(ProjectFolder) project; + for(int i = 0; i < projFolder.childCount; i++) { + searchInProject(projFolder.child(i), matchList, text); + } } else { + Log.d("Searching in: " ~ project.filename); EditableContent content = new EditableContent(true); content.load(project.filename); SearchMatchList match; @@ -141,16 +144,21 @@ class SearchWidget : TabWidget { if(match.matches.length > 0) { matchList ~= match; } + } } bool findText(dstring source) { Log.d("Finding " ~ source); + SearchMatchList[] matches; + _resultLog.text = ""d; //TODO Should not crash when in homepage. foreach(Project project; _frame._wsPanel.workspace.projects) { + Log.d("Searching in project " ~ project.filename); searchInProject(project.items, matches, source); + } if(matches.length == 0) { @@ -166,4 +174,4 @@ class SearchWidget : TabWidget { } return true; } -} \ No newline at end of file +} diff --git a/src/dlangide/workspace/project.d b/src/dlangide/workspace/project.d index 825ae76..0faf0d6 100644 --- a/src/dlangide/workspace/project.d +++ b/src/dlangide/workspace/project.d @@ -63,7 +63,7 @@ class ProjectItem { } /// returns true if item is folder - @property bool isFolder() { + @property const bool isFolder() { return false; } /// returns child object count @@ -84,7 +84,7 @@ class ProjectFolder : ProjectItem { super(filename); } - @property override bool isFolder() { + @property override const bool isFolder() { return true; } @property override int childCount() { @@ -135,21 +135,6 @@ class ProjectFolder : ProjectItem { return path; return buildNormalizedPath(_filename, path); } - - int begin; - int end; - bool empty() const { - return begin == _children.count; - } - - void popFront() - { - ++begin; - } - - ProjectItem front() { - return _children[begin]; - } } /// Project source file From 057dfa66ab8d3ed920cb04607fc2812efd08475a Mon Sep 17 00:00:00 2001 From: Hans-Albert Maritz Date: Tue, 10 Mar 2015 13:48:18 +1100 Subject: [PATCH 6/9] CTRL+F to open search tab --- src/dlangide/ui/commands.d | 2 ++ src/dlangide/ui/frame.d | 18 ++++++++++++------ src/dlangide/ui/searchPanel.d | 1 + views/res/i18n/en.ini | 4 +++- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/dlangide/ui/commands.d b/src/dlangide/ui/commands.d index f1b68ba..72979e1 100644 --- a/src/dlangide/ui/commands.d +++ b/src/dlangide/ui/commands.d @@ -44,6 +44,7 @@ enum IDEActions : int { GoToDefinition, GetCompletionSuggestions, InsertCompletion, + FindText, } __gshared static this() { @@ -101,3 +102,4 @@ const Action ACTION_ADD_TO_CURRENT_WORKSPACE = new Action(IDEActions.AddToCurren const Action ACTION_GO_TO_DEFINITION = (new Action(IDEActions.GoToDefinition, "GO_TO_DEFINITION"c, ""c, KeyCode.KEY_G, KeyFlag.Control)).addAccelerator(KeyCode.F12, 0).disableByDefault(); const Action ACTION_GET_COMPLETIONS = (new Action(IDEActions.GetCompletionSuggestions, "SHOW_COMPLETIONS"c, ""c, KeyCode.KEY_G, KeyFlag.Control|KeyFlag.Shift)).addAccelerator(KeyCode.SPACE, KeyFlag.Control).disableByDefault(); +const Action ACTION_FIND_TEXT = (new Action(IDEActions.FindText, "FIND_TEXT"c, ""c, KeyCode.KEY_F, KeyFlag.Control)); diff --git a/src/dlangide/ui/frame.d b/src/dlangide/ui/frame.d index d9ce14c..23a06df 100644 --- a/src/dlangide/ui/frame.d +++ b/src/dlangide/ui/frame.d @@ -367,11 +367,6 @@ class IDEFrame : AppFrame { _logPanel.appendText(null, "cannot start dcd-server: code completion for D code will not work"d); } - import dlangide.ui.searchPanel; - auto searchPanel = new SearchWidget("search", this); - - _logPanel.getTabs.addTab( searchPanel, "Search"d, null, true); - _dockHost.addDockedWindow(_logPanel); return _dockHost; @@ -390,7 +385,7 @@ class IDEFrame : AppFrame { MenuItem editItem = new MenuItem(new Action(2, "MENU_EDIT")); editItem.add(ACTION_EDIT_COPY, ACTION_EDIT_PASTE, - ACTION_EDIT_CUT, ACTION_EDIT_UNDO, ACTION_EDIT_REDO); + ACTION_EDIT_CUT, ACTION_EDIT_UNDO, ACTION_EDIT_REDO, ACTION_FIND_TEXT); MenuItem editItemAdvanced = new MenuItem(new Action(221, "MENU_EDIT_ADVANCED")); editItemAdvanced.add(ACTION_EDIT_INDENT, ACTION_EDIT_UNINDENT, ACTION_EDIT_TOGGLE_LINE_COMMENT, ACTION_EDIT_TOGGLE_BLOCK_COMMENT, ACTION_GO_TO_DEFINITION, ACTION_GET_COMPLETIONS); editItem.add(editItemAdvanced); @@ -631,6 +626,17 @@ class IDEFrame : AppFrame { case IDEActions.EditPreferences: showPreferences(); return true; + case IDEActions.FindText: + Log.d("Opening Search Field"); + import dlangide.ui.searchPanel; + int searchPanelIndex = _logPanel.getTabs.tabIndex("search"); + if(searchPanelIndex == -1) { + SearchWidget searchPanel = new SearchWidget("search", this); + _logPanel.getTabs.addTab( searchPanel, "Search"d, null, true); + } + _logPanel.getTabs.selectTab("search"); + //TODO: Focus search field + return true; default: return super.handleAction(a); } diff --git a/src/dlangide/ui/searchPanel.d b/src/dlangide/ui/searchPanel.d index 15e3026..2b63e22 100644 --- a/src/dlangide/ui/searchPanel.d +++ b/src/dlangide/ui/searchPanel.d @@ -6,6 +6,7 @@ import dlangui.core.editable; import dlangide.ui.frame; import dlangide.ui.wspanel; +import dlangui.widgets.tabs; //TODO: This is required for navigating to decleration of TabWidget / BUG import dlangide.workspace.workspace; import dlangide.workspace.project; diff --git a/views/res/i18n/en.ini b/views/res/i18n/en.ini index 68922e4..59b8987 100644 --- a/views/res/i18n/en.ini +++ b/views/res/i18n/en.ini @@ -56,9 +56,11 @@ MENU_WINDOW_CLOSE_ALL_DOCUMENTS=Close All Documents MENU_HELP=&HELP MENU_HELP_VIEW_HELP=&View help MENU_HELP_ABOUT=&About +MENU_NAVIGATE=NAVIGATE + GO_TO_DEFINITION=Go To Definition SHOW_COMPLETIONS=Get Autocompletions -MENU_NAVIGATE=NAVIGATE +FIND_TEXT=Find text TAB_LONG_LIST=Long list From ceccd53123e803bf7a2b0f8ad1270b0d09875c6c Mon Sep 17 00:00:00 2001 From: Hans-Albert Maritz Date: Tue, 10 Mar 2015 15:12:49 +1100 Subject: [PATCH 7/9] Added click on search result to open match location --- src/dlangide/ui/searchPanel.d | 79 +++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/src/dlangide/ui/searchPanel.d b/src/dlangide/ui/searchPanel.d index 2b63e22..1a771c2 100644 --- a/src/dlangide/ui/searchPanel.d +++ b/src/dlangide/ui/searchPanel.d @@ -1,4 +1,4 @@ -module dlangide.ui.searchPanel; +module dlangide.ui.searchPanel; import dlangui; @@ -6,19 +6,24 @@ import dlangui.core.editable; import dlangide.ui.frame; import dlangide.ui.wspanel; -import dlangui.widgets.tabs; //TODO: This is required for navigating to decleration of TabWidget / BUG +//import dlangui.widgets.tabs; //TODO: This is required for navigating to decleration of TabWidget / BUG import dlangide.workspace.workspace; import dlangide.workspace.project; import std.string; import std.conv; +interface SearchResultClickHandler { + bool onSearchResultClick(int line); +} + class SearchLogWidget : LogWidget { + Signal!SearchResultClickHandler searchResultClickHandler; + this(string ID){ super(ID); scrollLock = false; - } override protected CustomCharProps[] handleCustomLineHighlight(int line, dstring txt, ref CustomCharProps[] buf) { @@ -72,14 +77,29 @@ class SearchLogWidget : LogWidget { return colors; } } + + auto getCaretPos() { return _caretPos; } + + override bool onMouseEvent(MouseEvent event) { + super.onMouseEvent(event); + if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) { + int line = _caretPos.line; + if (searchResultClickHandler.assigned) { + searchResultClickHandler(line); + return true; + } + } + return false; + } } class SearchWidget : TabWidget { HorizontalLayout _layout; EditLine _findText; - LogWidget _resultLog; + SearchLogWidget _resultLog; protected IDEFrame _frame; + protected SearchMatchList[] _matchedList; struct SearchMatch { int line; @@ -95,6 +115,7 @@ class SearchWidget : TabWidget { this(string ID, IDEFrame frame) { super(ID); _frame = frame; + layoutHeight(FILL_PARENT); //Remove title, more button @@ -117,15 +138,16 @@ class SearchWidget : TabWidget { addChild(_layout); _resultLog = new SearchLogWidget("SearchLogWidget"); + _resultLog.searchResultClickHandler = &onMatchClick; _resultLog.layoutHeight(FILL_PARENT); addChild(_resultLog); } - void searchInProject(ProjectItem project, ref SearchMatchList[] matchList, dstring text) { - if(project.isFolder == true) { + void searchInProject(ProjectItem project, dstring text) { + if (project.isFolder == true) { ProjectFolder projFolder = cast(ProjectFolder) project; - for(int i = 0; i < projFolder.childCount; i++) { - searchInProject(projFolder.child(i), matchList, text); + for (int i = 0; i < projFolder.childCount; i++) { + searchInProject(projFolder.child(i), text); } } else { @@ -137,42 +159,63 @@ class SearchWidget : TabWidget { foreach(int lineIndex, dstring line; content.lines) { auto colIndex = line.indexOf(text); - if( colIndex != -1) { - match.matches ~= SearchMatch(lineIndex+1, colIndex, line); + if (colIndex != -1) { + match.matches ~= SearchMatch(lineIndex, colIndex, line); } } if(match.matches.length > 0) { - matchList ~= match; + _matchedList ~= match; } - } } bool findText(dstring source) { Log.d("Finding " ~ source); - SearchMatchList[] matches; _resultLog.text = ""d; + _matchedList = []; + //TODO Should not crash when in homepage. foreach(Project project; _frame._wsPanel.workspace.projects) { Log.d("Searching in project " ~ project.filename); - searchInProject(project.items, matches, source); - + searchInProject(project.items, source); } - if(matches.length == 0) { + if (_matchedList.length == 0) { _resultLog.appendText(to!dstring("No matches found.\n")); } else { - foreach(SearchMatchList fileMatchList; matches) { + foreach(SearchMatchList fileMatchList; _matchedList) { _resultLog.appendText("Matches in "d ~ to!dstring(fileMatchList.filename) ~ '\n'); foreach(SearchMatch match; fileMatchList.matches) { - _resultLog.appendText(" --> ["d ~ to!dstring(match.line) ~ ":"d ~ to!dstring(match.col) ~ "]" ~ match.lineContent ~"\n"d); + _resultLog.appendText(" --> ["d ~ to!dstring(match.line+1) ~ ":"d ~ to!dstring(match.col) ~ "]" ~ match.lineContent ~"\n"d); } } } return true; } + + bool onMatchClick(int line) { + line++; + foreach(matchList; _matchedList){ + line--; + if (line == 0) { + _frame.openSourceFile(matchList.filename); + _frame.currentEditor.setFocus(); + return true; + } + foreach(match; matchList.matches) { + line--; + if (line == 0) { + _frame.openSourceFile(matchList.filename); + _frame.currentEditor.setCaretPos(match.line, to!int(match.col)); + _frame.currentEditor.setFocus(); + return true; + } + } + } + return false; + } } From 3c2d3d53d7f0ab4062a95595a4db4f16db82c742 Mon Sep 17 00:00:00 2001 From: Hans-Albert Maritz Date: Tue, 10 Mar 2015 15:28:15 +1100 Subject: [PATCH 8/9] Added comments and cleanup --- src/dlangide/ui/searchPanel.d | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/dlangide/ui/searchPanel.d b/src/dlangide/ui/searchPanel.d index 1a771c2..d83ae06 100644 --- a/src/dlangide/ui/searchPanel.d +++ b/src/dlangide/ui/searchPanel.d @@ -2,11 +2,9 @@ module dlangide.ui.searchPanel; import dlangui; -import dlangui.core.editable; import dlangide.ui.frame; import dlangide.ui.wspanel; -//import dlangui.widgets.tabs; //TODO: This is required for navigating to decleration of TabWidget / BUG import dlangide.workspace.workspace; import dlangide.workspace.project; @@ -17,8 +15,10 @@ interface SearchResultClickHandler { bool onSearchResultClick(int line); } +//LogWidget with highlighting for search results. class SearchLogWidget : LogWidget { + //Sends which line was clicked. Signal!SearchResultClickHandler searchResultClickHandler; this(string ID){ @@ -35,6 +35,8 @@ class SearchLogWidget : LogWidget { uint flags = 0; if (buf.length < txt.length) buf.length = txt.length; + + //Highlights the filename if(txt.startsWith("Matches in ")) { CustomCharProps[] colors = buf[0..txt.length]; uint cl = defColor; @@ -49,7 +51,8 @@ class SearchLogWidget : LogWidget { colors[i].textFlags = flags; } return colors; - } + } + //Highlight line and collumn else { CustomCharProps[] colors = buf[0..txt.length]; uint cl = filenameColor; @@ -68,7 +71,7 @@ class SearchLogWidget : LogWidget { colors[i].color = cl; colors[i].textFlags = flags; - //Colors to applay after current character. + //Colors to apply in following iterations of the loop. if(rest.startsWith("]")) { cl = defColor; flags = 0; @@ -78,8 +81,6 @@ class SearchLogWidget : LogWidget { } } - auto getCaretPos() { return _caretPos; } - override bool onMouseEvent(MouseEvent event) { super.onMouseEvent(event); if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) { @@ -143,6 +144,7 @@ class SearchWidget : TabWidget { addChild(_resultLog); } + //Recursively search for text in projectItem void searchInProject(ProjectItem project, dstring text) { if (project.isFolder == true) { ProjectFolder projFolder = cast(ProjectFolder) project; @@ -197,6 +199,7 @@ class SearchWidget : TabWidget { return true; } + //Find the match/matchList that corrosponds to the line in _resultLog bool onMatchClick(int line) { line++; foreach(matchList; _matchedList){ From 9450328581d40deda69f73217aaefccd730a6b63 Mon Sep 17 00:00:00 2001 From: Hans-Albert Maritz Date: Tue, 10 Mar 2015 16:16:36 +1100 Subject: [PATCH 9/9] Added different search scopes --- src/dlangide/ui/searchPanel.d | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/dlangide/ui/searchPanel.d b/src/dlangide/ui/searchPanel.d index d83ae06..b3445e9 100644 --- a/src/dlangide/ui/searchPanel.d +++ b/src/dlangide/ui/searchPanel.d @@ -98,6 +98,7 @@ class SearchWidget : TabWidget { HorizontalLayout _layout; EditLine _findText; SearchLogWidget _resultLog; + ComboBox _searchScope; protected IDEFrame _frame; protected SearchMatchList[] _matchedList; @@ -136,6 +137,10 @@ class SearchWidget : TabWidget { return true; }); _layout.addChild(goButton); + + _searchScope = new ComboBox("searchScope", ["File"d, "Project"d, "Dependencies"d, "Everywhere"d]); + _searchScope.selectedItemIndex = 0; + _layout.addChild(_searchScope); addChild(_layout); _resultLog = new SearchLogWidget("SearchLogWidget"); @@ -178,11 +183,31 @@ class SearchWidget : TabWidget { _resultLog.text = ""d; _matchedList = []; - //TODO Should not crash when in homepage. - - foreach(Project project; _frame._wsPanel.workspace.projects) { - Log.d("Searching in project " ~ project.filename); - searchInProject(project.items, source); + switch (_searchScope.text) { + case "File": //File + auto currentFileItem = _frame._wsPanel.workspace.findSourceFileItem(_frame.currentEditor.filename); + if(currentFileItem !is null) + searchInProject(currentFileItem, source); + break; + case "Project": //Project + foreach(Project project; _frame._wsPanel.workspace.projects) { + if(!project.isDependency) + searchInProject(project.items, source); + } + break; + case "Dependencies": //Dependencies + foreach(Project project; _frame._wsPanel.workspace.projects) { + if(project.isDependency) + searchInProject(project.items, source); + } + break; + case "Everywhere": //Everywhere + foreach(Project project; _frame._wsPanel.workspace.projects) { + searchInProject(project.items, source); + } + break; + default: + assert(0); } if (_matchedList.length == 0) {