28 Commits 11dfc0bdaa ... e0383ed834

Author SHA1 Message Date
  David Ulrich e0383ed834 somehow semicolon got deleted 1 week ago
  David Ulrich c8dcfe6119 repane tab functions 2 weeks ago
  David Ulrich cdf094920b Merge branch 'master' into f_smartalign 4 weeks ago
  David Ulrich 1ba41206b0 avoid bg double draw for non-selected characters 4 weeks ago
  David Ulrich a80cd8820b Merge branch 'master' of notabug.org:/yzziizzy/gpuedit 4 weeks ago
  David Ulrich 9abfcfb5a2 avoid extra space when sep is space 4 weeks ago
  David Ulrich 786f99ce0e Merge branch 'master' of notabug.org:/yzziizzy/gpuedit into f_smartalign 4 weeks ago
  David Ulrich 7bf6039273 smart align is a little smarter now 1 month ago
  David Ulrich 8fa161bb57 able to smart align sometimes 1 month ago
  David Ulrich f06c522921 Merge branch 'master' into f_smartalign 1 month ago
  David Ulrich d0e71f1c51 per pane tab limit (auto-close oldest) 2 months ago
  David Ulrich 2923d920ab new command focus fix 2 months ago
  David Ulrich 968f70ae6a quick open/jump to same file opposite 2 months ago
  David Ulrich 17e1136f67 startup crash file open in multiple panes 2 months ago
  David Ulrich f9a7a463af basic tab drag reorder (same pane) 2 months ago
  David Ulrich 39bc6a7f8b open conjugate pane targeter, focus fix 2 months ago
  David Ulrich 2372116ab8 pcre was expected, new command options to reference json 3 months ago
  David Ulrich 069ec6cda7 less confusing pane targeter logic 3 months ago
  David Ulrich 99708c435c scaffold pane targeting command option 4 months ago
  David Ulrich 9d905aa661 fix missing file related crashes 4 months ago
  David Ulrich 501c346475 grep/fuzzy open tabs in session, memory bugfixes 4 months ago
  David Ulrich 0e2d6ecd75 Merge branch 'master' of notabug.org:/yzziizzy/gpuedit 5 months ago
  David Ulrich 8b2f862b34 prevent multiple session file writes during startup 6 months ago
  David Ulrich 6ef9ec2e4c Merge branch 'master' of notabug.org:/yzziizzy/gpuedit 6 months ago
  David Ulrich 3a4660d4bf broken wip 6 months ago
  David Ulrich 41c6fb3e4d Merge branch 'master' of notabug.org:/yzziizzy/gpuedit 7 months ago
  David Ulrich 034b939f2f Merge branch 'master' of notabug.org:/yzziizzy/gpuedit 7 months ago
  David Ulrich a4081323dc add format to SmartBubbleSelection 7 months ago
10 changed files with 316 additions and 16 deletions
  1. 30 9
      config/commands.json
  2. 1 0
      config/options.json
  3. 36 2
      src/app.c
  4. 2 0
      src/buffer.h
  5. 231 0
      src/bufferEditControl.c
  6. 10 3
      src/bufferEditor.c
  7. 1 1
      src/bufferLine.c
  8. 1 1
      src/buffer_drawing.c
  9. 4 0
      src/commands.h
  10. 0 0
      src/fileBrowser.c

+ 30 - 9
config/commands.json

@@ -33,17 +33,23 @@
 			{mode: 10, elem: "Main", cmd: "ExpandPanesY",   mods: "S",  key: "y", amt: -1},
 			{mode: 10, elem: "Main", cmd: "ExpandPanesY",   mods: "S",  key: "y", amt: -1},
 			
 			
 			
 			
-			{elem: "Main", cmd: "NextTab",  mods: "A",  key: "XK_Right", amt: 1},
-			{elem: "Main", cmd: "PrevTab",  mods: "A",  key: "XK_Left", amt: 1},
-			{elem: "Main", cmd: "MoveTabR", mods: "AS", key: "XK_Right", amt: 1},
-			{elem: "Main", cmd: "MoveTabL", mods: "AS", key: "XK_Left", amt: 1},
-			{elem: "Main", cmd: "SortTabs", mods: "AS", key: "s", amt: 1},
+			{elem: "Main", cmd: "NextTab",    mods: "A",   key: "XK_Right", amt: 1},
+			{elem: "Main", cmd: "PrevTab",    mods: "A",   key: "XK_Left",  amt: 1},
+			{elem: "Main", cmd: "MoveTabR",   mods: "AS",  key: "XK_Right", amt: 1},
+			{elem: "Main", cmd: "MoveTabL",   mods: "AS",  key: "XK_Left",  amt: 1},
+			{elem: "Main", cmd: "SortTabs",   mods: "AS",  key: "s",        amt: 1},
+			{elem: "Main", cmd: "RepaneTabH", mods: "CAS", key: "XK_Right", amt: 1},
+			{elem: "Main", cmd: "RepaneTabH", mods: "CAS", key: "XK_Left",  amt: -1},
+			{elem: "Main", cmd: "RepaneTabV", mods: "CAS", key: "XK_Up",    amt: 1},
+			{elem: "Main", cmd: "RepaneTabV", mods: "CAS", key: "XK_Down",  amt: -1},
+			
 			
 			
 			{elem: "Main", cmd: "FocusPaneRelX", mods: "AT", key: "XK_Right", amt: 1},
 			{elem: "Main", cmd: "FocusPaneRelX", mods: "AT", key: "XK_Right", amt: 1},
 			{elem: "Main", cmd: "FocusPaneRelX", mods: "AT", key: "XK_Left", amt: -1},
 			{elem: "Main", cmd: "FocusPaneRelX", mods: "AT", key: "XK_Left", amt: -1},
 			{elem: "Main", cmd: "FocusPaneRelY", mods: "AT", key: "XK_Up", amt: -1},
 			{elem: "Main", cmd: "FocusPaneRelY", mods: "AT", key: "XK_Up", amt: -1},
 			{elem: "Main", cmd: "FocusPaneRelY", mods: "AT", key: "XK_Down", amt: 1},
 			{elem: "Main", cmd: "FocusPaneRelY", mods: "AT", key: "XK_Down", amt: 1},
 			
 			
+			
 			{elem: "Main", cmd: "GoToTab", mods: "A", key: "1", amt: 0},
 			{elem: "Main", cmd: "GoToTab", mods: "A", key: "1", amt: 0},
 			{elem: "Main", cmd: "GoToTab", mods: "A", key: "2", amt: 1},
 			{elem: "Main", cmd: "GoToTab", mods: "A", key: "2", amt: 1},
 			{elem: "Main", cmd: "GoToTab", mods: "A", key: "3", amt: 2},
 			{elem: "Main", cmd: "GoToTab", mods: "A", key: "3", amt: 2},
@@ -57,8 +63,8 @@
 			
 			
 			{elem: "Main", cmd: "QuitWithoutSave", mods: "CS", key: "q", amt: 0},
 			{elem: "Main", cmd: "QuitWithoutSave", mods: "CS", key: "q", amt: 0},
 			{elem: "Main", cmd: "OpenFileBrowser", mods: "", key: "XK_F2", amt: 0},
 			{elem: "Main", cmd: "OpenFileBrowser", mods: "", key: "XK_F2", amt: 0},
-			{elem: "Main", cmd: "FuzzyOpener", mods: "", key: "XK_F4", amt: 0},
-			{elem: "Main", cmd: "GrepOpen", mods: "CS", key: "g", amt: 0},
+//			{elem: "Main", cmd: "FuzzyOpener", mods: "", key: "XK_F4", amt: 0}, // fuzzy opener block below
+//			{elem: "Main", cmd: "GrepOpen", mods: "CS", key: "g", amt: 0}, // grep opener block below
 			{elem: "Main", cmd: "Calculator", mods: "T", key: "/", amt: 0},
 			{elem: "Main", cmd: "Calculator", mods: "T", key: "/", amt: 0},
 			{elem: "Main", cmd: "SimpleWindowTest", mods: "C", key: "u", amt: 0},
 			{elem: "Main", cmd: "SimpleWindowTest", mods: "C", key: "u", amt: 0},
 			{elem: "Main", cmd: "CloseTab", mods: "CS", key: "w", amt: 0},
 			{elem: "Main", cmd: "CloseTab", mods: "CS", key: "w", amt: 0},
@@ -67,7 +73,7 @@
 			{elem: "Main", cmd: "Terminal", mods: "T", key: "t", amt: 0},
 			{elem: "Main", cmd: "Terminal", mods: "T", key: "t", amt: 0},
 			
 			
 			{elem: "Main", cmd: "OpenConjugate", mods: "C", key: "h", amt: ["c", "h"]},
 			{elem: "Main", cmd: "OpenConjugate", mods: "C", key: "h", amt: ["c", "h"]},
-			
+//			{elem: "Main", cmd: "OpenSelf", mods: "CS", key: "o", pane: "o", amt: 0}, // open/jump to same file in other pane
 			
 			
 			{elem: "Main", cmd: "FontNudgeWidth", mods: "CAT", key: "XK_Next", amt: -1},
 			{elem: "Main", cmd: "FontNudgeWidth", mods: "CAT", key: "XK_Next", amt: -1},
 			{elem: "Main", cmd: "FontNudgeWidth", mods: "CAT", key: "XK_Prior", amt: 1},
 			{elem: "Main", cmd: "FontNudgeWidth", mods: "CAT", key: "XK_Prior", amt: 1},
@@ -76,16 +82,29 @@
 			
 			
 			{elem: "Buffer", cmd: "ToggleGDBBreakpoint", mods: "A", key: "b", amt: 0},
 			{elem: "Buffer", cmd: "ToggleGDBBreakpoint", mods: "A", key: "b", amt: 0},
 			
 			
+			
+			{elem: "Main", cmd: "FuzzyOpener", mods: "", key: "XK_F4", amt: 0},
 			{elem: "FuzzyMatcher", cmd: "Exit", mods: "", key: "XK_Escape", amt: 0},
 			{elem: "FuzzyMatcher", cmd: "Exit", mods: "", key: "XK_Escape", amt: 0},
 			{elem: "FuzzyMatcher", cmd: "MoveCursorV", mods: "", key: "XK_Up", amt: -1},
 			{elem: "FuzzyMatcher", cmd: "MoveCursorV", mods: "", key: "XK_Up", amt: -1},
 			{elem: "FuzzyMatcher", cmd: "MoveCursorV", mods: "", key: "XK_Down", amt: 1},
 			{elem: "FuzzyMatcher", cmd: "MoveCursorV", mods: "", key: "XK_Down", amt: 1},
 			{elem: "FuzzyMatcher", cmd: "OpenFile", mods: "", key: "XK_Return", amt: 0},
 			{elem: "FuzzyMatcher", cmd: "OpenFile", mods: "", key: "XK_Return", amt: 0},
 			
 			
+			
+			{elem: "Main", cmd: "GrepOpen", mods: "CS", key: "g", amt: 0},
+			// abusive amount, 1st element is a format string, 2nd is a charset
+			{elem: "Buffer", cmd: "SmartBubbleSelection", mods: "CS", key: "g", amt: ["%s", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"], },
+			{elem: "Buffer", cmd: "SmartBubbleSelection", mods: "CA", key: "g", pane: "o", amt: ["%s", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"], },
+			// pane: "o" causes the command to target "other" pane,
+			// i.e. the first pane that is not the focused pane
+			{elem: "Buffer", cmd: "SmartBubbleSelection", mods: "CS", key: "t", amt: ["typedef.+\\b%s", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"] },
+			{elem: "Buffer", cmd: "SmartBubbleSelection", mods: "CA", key: "t", pane: "o", amt: ["typedef.+\\b%s", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"] },
+			
 			{elem: "GrepOpen", cmd: "Exit", mods: "", key: "XK_Escape", amt: 0},
 			{elem: "GrepOpen", cmd: "Exit", mods: "", key: "XK_Escape", amt: 0},
 			{elem: "GrepOpen", cmd: "MoveCursorV", mods: "", key: "XK_Up", amt: -1},
 			{elem: "GrepOpen", cmd: "MoveCursorV", mods: "", key: "XK_Up", amt: -1},
 			{elem: "GrepOpen", cmd: "MoveCursorV", mods: "", key: "XK_Down", amt: 1},
 			{elem: "GrepOpen", cmd: "MoveCursorV", mods: "", key: "XK_Down", amt: 1},
 			{elem: "GrepOpen", cmd: "OpenFile", mods: "", key: "XK_Return", amt: 0},
 			{elem: "GrepOpen", cmd: "OpenFile", mods: "", key: "XK_Return", amt: 0},
 			
 			
+			
 			{elem: "FileBrowser", cmd: "CursorMoveNoWrap", mods: "", key: "XK_Up", amt: -1},
 			{elem: "FileBrowser", cmd: "CursorMoveNoWrap", mods: "", key: "XK_Up", amt: -1},
 			{elem: "FileBrowser", cmd: "CursorMoveNoWrap", mods: "", key: "XK_Down", amt: 1},
 			{elem: "FileBrowser", cmd: "CursorMoveNoWrap", mods: "", key: "XK_Down", amt: 1},
 			{elem: "FileBrowser", cmd: "CursorMoveNoWrap", mods: "C", key: "XK_Up", amt: -5},
 			{elem: "FileBrowser", cmd: "CursorMoveNoWrap", mods: "C", key: "XK_Up", amt: -5},
@@ -95,6 +114,9 @@
 			{elem: "FileBrowser", cmd: "ToggleSelect", mods: "", key: "XK_space", amt: 0},
 			{elem: "FileBrowser", cmd: "ToggleSelect", mods: "", key: "XK_space", amt: 0},
 			/*{elem: "FileBrowser", cmd: "JumpToLetter", mods: "", key: "", amt: 0}, */
 			/*{elem: "FileBrowser", cmd: "JumpToLetter", mods: "", key: "", amt: 0}, */
 			
 			
+			
+			{elem: "Buffer", cmd: "SmartAlign", mods: "CS", key: "a", amt 0, flags: ["rehighlight", "resetCursorBlink", "undoSeqBreak"]},
+			
 			{elem: "Buffer", cmd: "MoveCursorH", mods: "", key: "XK_Left", amt: -1, flags: ["provokeAC", "scrollToCursor", "resetCursorBlink", "undoSeqBreak"]},
 			{elem: "Buffer", cmd: "MoveCursorH", mods: "", key: "XK_Left", amt: -1, flags: ["provokeAC", "scrollToCursor", "resetCursorBlink", "undoSeqBreak"]},
 			{elem: "Buffer", cmd: "MoveCursorH", mods: "", key: "XK_Right", amt: 1, flags: ["provokeAC", "scrollToCursor", "resetCursorBlink", "undoSeqBreak"]},
 			{elem: "Buffer", cmd: "MoveCursorH", mods: "", key: "XK_Right", amt: 1, flags: ["provokeAC", "scrollToCursor", "resetCursorBlink", "undoSeqBreak"]},
 			{elem: "Buffer", cmd: "MoveCursorV", mods: "", key: "XK_Up", amt: -1, flags: ["provokeAC", "scrollToCursor", "resetCursorBlink", "undoSeqBreak"]},
 			{elem: "Buffer", cmd: "MoveCursorV", mods: "", key: "XK_Up", amt: -1, flags: ["provokeAC", "scrollToCursor", "resetCursorBlink", "undoSeqBreak"]},
@@ -141,7 +163,6 @@
 				amt: ["%s", "%c", "typedef struct %s {\n\t%c\n} %s;"], flags: ["scrollToCursor", "rehighlight", "undoSeqBreak"]},
 				amt: ["%s", "%c", "typedef struct %s {\n\t%c\n} %s;"], flags: ["scrollToCursor", "rehighlight", "undoSeqBreak"]},
 			{elem: "Buffer", cmd: "LineEnsureEnding", mods: "C", key: ";", amt: ";", flags: ["rehighlight", "undoSeqBreak"]},
 			{elem: "Buffer", cmd: "LineEnsureEnding", mods: "C", key: ";", amt: ";", flags: ["rehighlight", "undoSeqBreak"]},
 			{elem: "Buffer", cmd: "LineEnsureEnding", mods: "C", key: "{", amt: "{", flags: ["rehighlight", "undoSeqBreak"]},
 			{elem: "Buffer", cmd: "LineEnsureEnding", mods: "C", key: "{", amt: "{", flags: ["rehighlight", "undoSeqBreak"]},
-			{elem: "Buffer", cmd: "SmartBubbleSelection", mods: "CS", key: "p", amt: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_", },
 			{elem: "Buffer", cmd: "SmartComment", mods: "C", key: "d", amt: ["//", "/*", "*/"], flags: ["rehighlight", "undoSeqBreak"]},
 			{elem: "Buffer", cmd: "SmartComment", mods: "C", key: "d", amt: ["//", "/*", "*/"], flags: ["rehighlight", "undoSeqBreak"]},
 			{elem: "Buffer", cmd: "StrictUncomment", mods: "CS", key: "d", amt: ["//", "/*", "*/"], flags: ["rehighlight", "undoSeqBreak"]},
 			{elem: "Buffer", cmd: "StrictUncomment", mods: "CS", key: "d", amt: ["//", "/*", "*/"], flags: ["rehighlight", "undoSeqBreak"]},
 			{elem: "Buffer", cmd: "DeleteCurLine", mods: "C", key: "k", amt: 0, flags: ["scrollToCursor", "rehighlight", "undoSeqBreak"]},
 			{elem: "Buffer", cmd: "DeleteCurLine", mods: "C", key: "k", amt: 0, flags: ["scrollToCursor", "rehighlight", "undoSeqBreak"]},

+ 1 - 0
config/options.json

@@ -22,6 +22,7 @@ general: {
 	
 	
 	"MainControl_openInPlace": 0,
 	"MainControl_openInPlace": 0,
 	"MainControl_autoSortTabs": 0,
 	"MainControl_autoSortTabs": 0,
+//	MainControl_paneTabLimit: 8, // auto-close oldest (not pinned) tab after n tabs open
 
 
 	"MainControl_statusWidgets": [
 	"MainControl_statusWidgets": [
 //				{ type: "hello_world", size: 15, align: "r", "format": "" },
 //				{ type: "hello_world", size: 15, align: "r", "format": "" },

+ 36 - 2
src/app.c

@@ -256,13 +256,47 @@ void AppState_Init(AppState* as, int argc, char* argv[]) {
 					if(!path) continue;
 					if(!path) continue;
 					
 					
 					MainControlTab* mct = MainControlPane_LoadFile(pane, path);
 					MainControlTab* mct = MainControlPane_LoadFile(pane, path);
+					if(!mct) {
+						fprintf(stderr, "Error: could not open session file with path <%s>.\n", path);
+						continue;
+					}
+					
 					GUIBufferEditor_LoadSessionState((GUIBufferEditor*)mct->client, jdata);
 					GUIBufferEditor_LoadSessionState((GUIBufferEditor*)mct->client, jdata);
 					
 					
 					mct->accessIndex = json_obj_get_int(jtab, "accessIndex", 0);
 					mct->accessIndex = json_obj_get_int(jtab, "accessIndex", 0);
 					pane->lastTabAccessIndex = MAX(mct->accessIndex, pane->lastTabAccessIndex);
 					pane->lastTabAccessIndex = MAX(mct->accessIndex, pane->lastTabAccessIndex);
 				}
 				}
 				else if(0 == strcmp("FuzzyOpener", type)) {
 				else if(0 == strcmp("FuzzyOpener", type)) {
-					MainControlPane_FuzzyOpener(pane, "");
+					json_value_t* jdata = json_obj_get_val(jtab, "data");
+					
+					char* path = json_obj_get_str(jdata, "path");
+					printf("loading FuzzyOpener with path <%s>\n", path);
+					if(!path) path = "";
+					
+					MainControlTab* mct = MainControlPane_FuzzyOpener(pane, path);
+					if(!mct) {
+						fprintf(stderr, "Error: could not open session FuzzyOpener with path <%s>.\n", path);
+						continue;
+					}
+					
+					mct->accessIndex = json_obj_get_int(jtab, "accessIndex", 0);
+					pane->lastTabAccessIndex = MAX(mct->accessIndex, pane->lastTabAccessIndex);
+				}
+				else if(0 == strcmp("GrepOpener", type)) {
+					json_value_t* jdata = json_obj_get_val(jtab, "data");
+					
+					char* query = json_obj_get_str(jdata, "query");
+					printf("loading GrepOpener with query <%s>\n", query);
+					if(!query) query = "";
+					
+					MainControlTab* mct = MainControlPane_GrepOpen(pane, query);
+					if(!mct) {
+						fprintf(stderr, "Error: could not spawn session GrepOpener with query <%s>.\n", query);
+						continue;
+					}
+					
+					mct->accessIndex = json_obj_get_int(jtab, "accessIndex", 0);
+					pane->lastTabAccessIndex = MAX(mct->accessIndex, pane->lastTabAccessIndex);
 				}
 				}
 			}
 			}
 			
 			
@@ -306,7 +340,7 @@ void AppState_Init(AppState* as, int argc, char* argv[]) {
 		}
 		}
 		MainControlPane_GoToTab(as->mc->focusedPane, 0);
 		MainControlPane_GoToTab(as->mc->focusedPane, 0);
 	}
 	}
-	
+	as->mc->sessionLoaded = 1;
 //	as->mc->focusedPane = as->mc->paneSet[1];
 //	as->mc->focusedPane = as->mc->paneSet[1];
 //	MainControl_LoadFile(as->mc, "testfile.c");
 //	MainControl_LoadFile(as->mc, "testfile.c");
 //	MainControl_LoadFile(as->mc, "testfile.h");
 //	MainControl_LoadFile(as->mc, "testfile.h");

+ 2 - 0
src/buffer.h

@@ -856,6 +856,8 @@ void Buffer_PrintDict(Buffer* b);
 BufferACMatchSet* Buffer_FindDictMatches(Buffer* b, BufferRange* r);
 BufferACMatchSet* Buffer_FindDictMatches(Buffer* b, BufferRange* r);
 void GBEC_CancelAutocomplete(GUIBufferEditControl* w);
 void GBEC_CancelAutocomplete(GUIBufferEditControl* w);
 
 
+void GBEC_SmartAlign(GUIBufferEditControl* w, char* separator);
+
 // temp
 // temp
 int GUIBufferEditor_FindWord(GUIBufferEditor* w, char* word);
 int GUIBufferEditor_FindWord(GUIBufferEditor* w, char* word);
 
 

+ 231 - 0
src/bufferEditControl.c

@@ -860,6 +860,10 @@ int GBEC_ProcessCommand(GUIBufferEditControl* w, GUI_Cmd* cmd, int* needRehighli
 	
 	
 	switch(cmd->cmd) {
 	switch(cmd->cmd) {
 	
 	
+		case GUICMD_Buffer_SmartAlign:
+			GBEC_SmartAlign(w, cmd->str);
+			break;
+	
 		case GUICMD_Buffer_MacroToggleRecording: 
 		case GUICMD_Buffer_MacroToggleRecording: 
 			w->isRecording = !w->isRecording;
 			w->isRecording = !w->isRecording;
 			if(w->isRecording) {
 			if(w->isRecording) {
@@ -1601,6 +1605,233 @@ int GBEC_ProcessCommand(GUIBufferEditControl* w, GUI_Cmd* cmd, int* needRehighli
 
 
 
 
 
 
+
+
+/////////////////
+// SMART ALIGN //
+
+struct align_segment {
+	colnum_t a, b;
+	int len;
+};
+struct align_line {
+	BufferLine* bl;
+	int n_segs;
+	VEC(struct align_segment) segs;
+	int total_len;
+	
+	unsigned char last_empty;
+};
+
+
+void calculate_align_line(BufferLine* bl, char sep, struct align_line* al) {
+	al->bl = bl;
+	// walk the line looking for sep
+	int seeking = 1;
+	int seg_start = 0;
+	struct align_segment seg = {0};
+	for(int i = 0; i < bl->length; i++) {
+		if(bl->buf[i] == sep) {
+			if(seeking) {
+				seg.a = i;
+			}
+			seg.b = i;
+			seg.len = seg.b - seg.a;
+			al->n_segs++;
+			al->total_len += seg.len;
+			VEC_PUSH(&al->segs, seg);
+			
+			seeking = 1;
+			seg.a = 0;
+			seg.b = 0;
+			seg.len = 0;
+		} else if(seeking && bl->buf[i] == ' ') {
+			continue;
+		} else if(seeking) {
+			seg.a = i;
+			seeking = 0;			
+		}
+	}
+	
+	if(seeking) {
+		seg.a = bl->length;
+	}
+	
+	seg.b = bl->length;
+	seg.len = seg.b - seg.a;
+	al->n_segs++;
+	al->total_len += seg.len;
+	VEC_PUSH(&al->segs, seg);
+	
+	if(!seg.len) al->last_empty = 1;
+}
+
+
+void align_line_init(struct align_line* al) {
+	VEC_INIT(&al->segs);
+}
+
+
+void align_line_free(struct align_line* al) {
+	VEC_FREE(&al->segs);
+	free(al);
+}
+
+
+void GBEC_SmartAlign(GUIBufferEditControl* w, char* separator) {
+	int max_skip = 1; // config: skip <n> lines with non-matching segments
+	int min_spaces = 1; // config: ensure <n> spaces between segments
+//	char sep = separator[0]; // should be done for each separator; exercise for the reader
+	
+	// parse cursor line for canonical number of segments
+	struct align_line* al_ref;// = pcalloc(al_ref);
+	BufferLine* line_ref = CURSOR_LINE(w->sel);
+	char sep;
+//	align_line_init(al_ref);
+	
+	for(int i=0; separator[i]; i++) {
+		sep = separator[i];
+		al_ref = pcalloc(al_ref);
+		align_line_init(al_ref);
+		calculate_align_line(line_ref, sep, al_ref);
+		if(al_ref->n_segs - al_ref->last_empty > 1) break;
+		
+		printf("insufficient segments for alignment sep: <%c>\n", sep);
+		align_line_free(al_ref);
+		al_ref = NULL;
+	}
+	
+	if(!al_ref) return;
+	
+	VEC(struct align_line*) align_list;
+	VEC_INIT(&align_list);
+	VEC_PUSH(&align_list, al_ref);
+	BufferLine* next = line_ref->next;
+	BufferLine* prev = line_ref->prev;
+	int skip_next = 0,
+		skip_prev = 0;
+	
+	struct align_line *al_next, *al_prev;
+	while(next || prev) {
+		// get next line segments, if right amount push to align_list and set next
+		// else increment skip_next and set or null next
+		if(next) {
+//			printf("testing next buffer line %d (%p)\n", next->lineNum, next);
+			al_next = pcalloc(al_next);
+			align_line_init(al_next);
+			calculate_align_line(next, sep, al_next);
+			
+			if(al_next->n_segs == al_ref->n_segs) {
+				VEC_PUSH(&align_list, al_next);
+				skip_next = 0;
+				next = al_next->bl->next;
+			}
+			else if(skip_next < max_skip) {
+				skip_next++;
+				next = al_next->bl->next;
+				align_line_free(al_next);
+			}
+			else {
+				align_line_free(al_next);
+				next = NULL;
+			}
+		}
+		
+		// get prev line segments, if right amount push to align_list and set prev
+		// else increment skip_prev and set or null prev
+		if(prev) {
+//			printf("testing prev buffer line %d (%p)\n", prev->lineNum, prev);
+			al_prev = pcalloc(al_prev);
+			align_line_init(al_prev);
+			calculate_align_line(prev, sep, al_prev);
+			
+			if(al_prev->n_segs == al_ref->n_segs) {
+				VEC_PUSH(&align_list, al_prev);
+				skip_prev = 0;
+				prev = al_prev->bl->prev;
+			}
+			else if(skip_prev < max_skip) {
+				skip_prev++;
+				prev = al_prev->bl->prev;
+				align_line_free(al_prev);
+			}
+			else {
+				align_line_free(al_prev);
+				prev = NULL;
+			}
+		}
+	}
+	
+	int* seg_maxes = pcallocn(seg_maxes, al_ref->n_segs);
+	// find max length of each segment
+	VEC_EACH(&align_list, i, al) {
+		VEC_EACH(&al->segs, j, seg) {
+			if(seg.len > seg_maxes[j]) {
+				seg_maxes[j] = seg.len;
+			}
+		}
+	}
+	// then loop again and copy/pad the lines
+	struct align_segment seg_prev;
+	char* spaces = "                                                            ";
+	VEC_EACH(&align_list, i, al) {
+		int out_max = 1024;
+		int out_len = 0;
+		char* out_text = malloc(out_max*sizeof(*out_text));
+		VEC_EACH(&al->segs, j, seg) {
+			if(j > 0) {// && j < al->n_segs) {
+				 
+				
+				
+				int prev_diff = seg_maxes[j-1] + min_spaces - seg_prev.len;
+				int pad_len = MAX(prev_diff, min_spaces);
+				if(sep == ' ') {
+					pad_len = MAX(pad_len-1, 0);
+				}
+				
+				if(out_max < out_len + pad_len + 1 /*sep len*/) {
+					out_max *= 2;
+					out_text = realloc(out_text, out_max*sizeof(*out_text));
+				}
+				
+				out_text[out_len++] = sep;
+				memset(out_text+out_len*sizeof(*out_text), ' ', pad_len);
+				out_len += pad_len;
+				
+				
+				// copy this into the line:
+				// sep + MAX(min_spaces, prev_diff) spaces
+				
+			}
+			// copy al->bl[seg->a, seg->b] into new line
+//			printf("copying seg[%ld] of line[%d] (%d chars)\n", j, al->bl->lineNum, seg.len);
+			
+			if(out_max < out_len + seg.len) {
+				out_max *= 2;
+				out_text = realloc(out_text, out_max*sizeof(*out_text));
+			}
+			
+			memcpy(out_text+out_len*sizeof(*out_text), &al->bl->buf[seg.a], seg.len);
+			out_len += seg.len;
+			
+			seg_prev = seg;
+		}
+		Buffer_LineTruncateAfter(w->b, al->bl, 0);
+		Buffer_LineAppendText(w->b, al->bl, out_text, out_len);
+		free(out_text);
+	}
+	
+	// afterwards free remaining align_line data
+	VEC_EACH(&align_list, i, al) {
+		align_line_free(al);
+	}
+	
+	return;
+
+}
+
+
+
 void GBEC_CancelAutocomplete(GUIBufferEditControl* w) {
 void GBEC_CancelAutocomplete(GUIBufferEditControl* w) {
 	if(!w->autocompleteOptions) return;
 	if(!w->autocompleteOptions) return;
 	if(w->autocompleteOptions->matches) free(w->autocompleteOptions->matches);
 	if(w->autocompleteOptions->matches) free(w->autocompleteOptions->matches);

+ 10 - 3
src/bufferEditor.c

@@ -406,7 +406,8 @@ GUIBufferEditor* GUIBufferEditor_New(GUIManager* gm, MessagePipe* tx) {
 
 
 	
 	
 	GUIBufferEditor* w = pcalloc(w);
 	GUIBufferEditor* w = pcalloc(w);
-	w->gm = gm;	GUIString_Init(&w->findQuery);
+	w->gm = gm;
+	GUIString_Init(&w->findQuery);
 	GUIString_Init(&w->replaceText);
 	GUIString_Init(&w->replaceText);
 	
 	
 	w->ec = GUIBufferEditControl_New(gm);
 	w->ec = GUIBufferEditControl_New(gm);
@@ -1272,11 +1273,17 @@ int GUIBufferEditor_ProcessCommand(GUIBufferEditor* w, GUI_Cmd* cmd, int* needRe
 			BufferRange r = *w->ec->sel;
 			BufferRange r = *w->ec->sel;
 			
 			
 			if(!HAS_SELECTION(&r)) {
 			if(!HAS_SELECTION(&r)) {
-				Buffer_GetSequenceUnder(w->b, CURSOR_LINE(&r), CURSOR_COL(&r), cmd->str, &r);
+				Buffer_GetSequenceUnder(w->b, CURSOR_LINE(&r), CURSOR_COL(&r), cmd->pstr[1], &r);
 			}
 			}
 			
 			
 			char* s = Buffer_StringFromSelection(w->b, &r, NULL);
 			char* s = Buffer_StringFromSelection(w->b, &r, NULL);
-			MessagePipe_Send(w->tx, MSG_GrepOpener, s, NULL);
+			MessageGrepOpt opt = {0};
+			opt.searchTerm = sprintfdup(cmd->pstr[0], s);
+			free(s);
+			
+			opt.paneTargeter = cmd->paneTargeter;
+			MessagePipe_Send(w->tx, MSG_GrepOpener, &opt, NULL);
+			free(opt.searchTerm);
 			break;
 			break;
 			
 			
 		}
 		}

+ 1 - 1
src/bufferLine.c

@@ -24,7 +24,7 @@ void BufferLine_AppendLine(BufferLine* l, BufferLine* src) {
 
 
 
 
 void BufferLine_SetText(BufferLine* l, char* text, intptr_t len) {
 void BufferLine_SetText(BufferLine* l, char* text, intptr_t len) {
-	if(len == 0) {
+	if(len <= 0) {
 		l->length = 0;
 		l->length = 0;
 		return;
 		return;
 	};
 	};

+ 1 - 1
src/buffer_drawing.c

@@ -266,7 +266,7 @@ void GUIBufferEditControl_Draw(GUIBufferEditControl* gbe, GUIManager* gm, Vector
 						gm->curZ = z + 4;
 						gm->curZ = z + 4;
 						GUI_CharFont_NoGuard(c, V(tl.x + hsoff + adv, yoff), f, fsize, fg);
 						GUI_CharFont_NoGuard(c, V(tl.x + hsoff + adv, yoff), f, fsize, fg);
 						gm->curZ = z + 2;
 						gm->curZ = z + 2;
-						GUI_Rect(V(tl.x + adv + hsoff, yoff - ascender), V(MAX(5, (float)bs->charWidth), bs->lineHeight), bg);
+						if(inSelection) GUI_Rect(V(tl.x + adv + hsoff, yoff - ascender), V(MAX(5, (float)bs->charWidth), bs->lineHeight), bg);
 					}
 					}
 					
 					
 					adv += bs->charWidth;
 					adv += bs->charWidth;

+ 4 - 0
src/commands.h

@@ -129,6 +129,7 @@
 	X(Buffer, ScrollColsH) \
 	X(Buffer, ScrollColsH) \
 	X(Buffer, ScrollScreenPctH) \
 	X(Buffer, ScrollScreenPctH) \
 	X(Buffer, NextHighlighter) \
 	X(Buffer, NextHighlighter) \
+	X(Buffer, SmartAlign) \
 	X(Buffer, SmartBubbleSelection) \
 	X(Buffer, SmartBubbleSelection) \
 	X(Buffer, MacroToggleRecording) \
 	X(Buffer, MacroToggleRecording) \
 	X(Buffer, MacroReplay) \
 	X(Buffer, MacroReplay) \
@@ -183,6 +184,7 @@
 	X(Main, LoadFile) \
 	X(Main, LoadFile) \
 	X(Main, NewEmptyBuffer) \
 	X(Main, NewEmptyBuffer) \
 	X(Main, OpenConjugate) \
 	X(Main, OpenConjugate) \
+	X(Main, OpenSelf) \
 	X(Main, ReloadTab) \
 	X(Main, ReloadTab) \
 	X(Main, CloseTab) \
 	X(Main, CloseTab) \
 	X(Main, SaveAndCloseTab) \
 	X(Main, SaveAndCloseTab) \
@@ -191,6 +193,8 @@
 	X(Main, MoveTabR) \
 	X(Main, MoveTabR) \
 	X(Main, MoveTabL) \
 	X(Main, MoveTabL) \
 	X(Main, SortTabs) \
 	X(Main, SortTabs) \
+	X(Main, RepaneTabH) \
+	X(Main, RepaneTabV) \
 	X(Main, GoToTab) \
 	X(Main, GoToTab) \
 	X(Main, SplitPane) \
 	X(Main, SplitPane) \
 	X(Main, MainMenu) \
 	X(Main, MainMenu) \

+ 0 - 0
src/fileBrowser.c


Some files were not shown because too many files changed in this diff