Explorar el Código

Early support for line/statement moving

Brian Fiete hace 5 años
padre
commit
a650c7ab9c
Se han modificado 5 ficheros con 289 adiciones y 113 borrados
  1. 4 0
      IDE/src/Commands.bf
  2. 44 10
      IDE/src/IDEApp.bf
  3. 4 0
      IDE/src/Settings.bf
  4. 9 0
      IDE/src/VertDir.bf
  5. 228 103
      IDE/src/ui/SourceEditWidgetContent.bf

+ 4 - 0
IDE/src/Commands.bf

@@ -212,6 +212,10 @@ namespace IDE
 			Add("Make Uppercase", new () => { gApp.[Friend]ChangeCase(true); });
 			Add("Match Brace Select", new => gApp.Cmd_MatchBrace);
 			Add("Match Brace", new => gApp.Cmd_MatchBrace);
+			Add("Move Line Down", new () => gApp.Cmd_MoveLine(.Down));
+			Add("Move Line Up", new () => gApp.Cmd_MoveLine(.Up));
+			Add("Move Statement Down", new () => gApp.Cmd_MoveStatement(.Down));
+			Add("Move Statement Up", new () => gApp.Cmd_MoveStatement(.Up));
 			Add("Navigate Backwards", new => gApp.[Friend]NavigateBackwards);
 			Add("Navigate Forwards", new => gApp.[Friend]NavigateForwards);
 			Add("New Debug Session", new => gApp.Cmd_NewDebugSession);

+ 44 - 10
IDE/src/IDEApp.bf

@@ -2065,6 +2065,17 @@ namespace IDE
             	mBfResolveSystem.AddProject(project);
 #endif
 			mWorkspace.ClearProjectNameCache();
+
+			if (!mWorkspace.mLoading)
+			{
+				for (var checkProject in mWorkspace.mProjects)
+				{
+					int idx = checkProject.mDependencies.FindIndex(scope (dep) => dep.mProjectName == project.mProjectName);
+				    if (idx != -1)
+				        ProjectOptionsChanged(checkProject);
+				}
+				ProjectOptionsChanged(project, false);
+			}
         }
 
         public void AddNewProjectToWorkspace(Project project, VerSpecRecord verSpec = null)
@@ -2102,14 +2113,6 @@ namespace IDE
 			dep.mVerSpec = new .();
 			dep.mVerSpec.SetSemVer("*");
 			project.mDependencies.Add(dep);
-
-            for (var checkProject in mWorkspace.mProjects)
-            {
-				int idx = checkProject.mDependencies.FindIndex(scope (dep) => dep.mProjectName == project.mProjectName);
-                if (idx != -1)
-                    ProjectOptionsChanged(checkProject);
-            }
-            ProjectOptionsChanged(project, false);
         }
 
         public Project CreateProject(String projName, String projDir, Project.TargetType targetType)
@@ -2348,7 +2351,7 @@ namespace IDE
 				return .Err;
 		}
 
-		void FlushDeferredLoadProjects()
+		void FlushDeferredLoadProjects(bool addToUI = false)
 		{
 			while (true)
 			{
@@ -2369,6 +2372,8 @@ namespace IDE
 						}
 
 						AddProjectToWorkspace(project, false);
+						if (addToUI)
+							mProjectPanel.InitProject(project);
 					}
 				}
 				if (!hadLoad)
@@ -2401,7 +2406,13 @@ namespace IDE
 
 			bool isNew = false;
 			bool wantSave = false;
-            
+
+			mWorkspace.mLoading = true;
+			defer
+			{
+				mWorkspace.mLoading = false;
+			}
+
             if (StructuredLoad(data, workspaceFileName) case .Err(let err))
             {
 				mBeefConfig.Refresh();
@@ -3668,6 +3679,22 @@ namespace IDE
 				sourceViewPanel.MatchBrace();
 		}
 
+		[IDECommand]
+		public void Cmd_MoveLine(VertDir dir)
+		{
+			var sewc = GetActiveSourceEditWidgetContent();
+			if (sewc != null)
+				sewc.MoveLine(dir);
+		}
+
+		[IDECommand]
+		public void Cmd_MoveStatement(VertDir dir)
+		{
+			var sewc = GetActiveSourceEditWidgetContent();
+			if (sewc != null)
+				sewc.MoveStatement(dir);
+		}
+
 		[IDECommand]
 		public void Cmd_GotoNextItem()
 		{
@@ -5169,6 +5196,12 @@ namespace IDE
 			AddMenuItem(bookmarkMenu, "&Clear Bookmarks", "Bookmark Clear");
 
 			var advancedEditMenu = subMenu.AddMenuItem("Advanced");
+			AddMenuItem(advancedEditMenu, "Duplicate Line", "Duplicate Line");
+			AddMenuItem(advancedEditMenu, "Move Line Up", "Move Line Up");
+			AddMenuItem(advancedEditMenu, "Move Line Down", "Move Line Down");
+			AddMenuItem(advancedEditMenu, "Move Statement Up", "Move Statement Up");
+			AddMenuItem(advancedEditMenu, "Move Statement Down", "Move Statement Down");
+			advancedEditMenu.AddMenuItem(null);
 			AddMenuItem(advancedEditMenu, "Make Uppercase", "Make Uppercase");
 			AddMenuItem(advancedEditMenu, "Make Lowercase", "Make Lowercase");
 			mViewWhiteSpace.mMenu = AddMenuItem(advancedEditMenu, "View White Space", "View White Space", null, null, true, mViewWhiteSpace.Bool ? 1 : 0);
@@ -8692,6 +8725,7 @@ namespace IDE
         {
 			RemoveProjectItems(project);
 
+			project.mDeleted = true;
             mWorkspace.SetChanged();
             mWorkspace.mProjects.Remove(project);
 #if IDE_C_SUPPORT

+ 4 - 0
IDE/src/Settings.bf

@@ -687,6 +687,10 @@ namespace IDE
 				Add("Make Uppercase", "Ctrl+Shift+U");
 				Add("Match Brace Select", "Ctrl+Shift+RBracket");
 				Add("Match Brace", "Ctrl+RBracket");
+				Add("Move Line Down", "Alt+Shift+Down");
+				Add("Move Line Up", "Alt+Shift+Up");
+				Add("Move Statement Down", "Ctrl+Shift+Down");
+				Add("Move Statement Up", "Ctrl+Shift+Up");
 				Add("Navigate Backwards", "Alt+Left");
 				Add("Navigate Forwards", "Alt+Right");
 				Add("Next Document Panel", "Ctrl+Comma");

+ 9 - 0
IDE/src/VertDir.bf

@@ -0,0 +1,9 @@
+namespace IDE
+{
+	enum VertDir
+	{
+		Up = -1,
+		None = 0,
+		Down = 1
+	}
+}

+ 228 - 103
IDE/src/ui/SourceEditWidgetContent.bf

@@ -2139,21 +2139,51 @@ namespace IDE.ui
 			mData.mUndoManager.Add(undoBatchStart.mBatchEnd);
 		}
 
-		bool GetStatementRange(int checkIdx, out int startIdx, out int endIdx, out char8 endChar)
+		enum StatementRangeFlags
 		{
+			None,
+			IncludeBlock,
+			AllowInnerMethodSelect
+		}
+
+		enum StatementKind
+		{
+			None,
+			Normal,
+			Method
+		}
+
+		StatementKind GetStatementRange(int startCheckPos, StatementRangeFlags flags, out int startIdx, out int endIdx, out char8 endChar)
+		{
+			StatementKind statementKind = .Normal;
 			startIdx = -1;
 			endIdx = -1;
 			endChar = 0;
 
-			GetLineCharAtIdx(checkIdx, var line, var lineChar);
+			GetLineCharAtIdx(startCheckPos, var line, var lineChar);
 			GetBlockStart(line, var foundBlockStartIdx, var blockOpenSpaceCount);
 
+			if (foundBlockStartIdx < 0)
+				return .None;
+
 			bool expectingStatement = true;
+			int stmtCommentStart = -1;
 			int stmtStart = -1;
 
+			int prevLineEnd = -1;
 			int lastNonWS = -1;
 			int parenCount = 0;
 			int lastCrPos = -1;
+			int braceCount = 0;
+			int innerBraceCount = 0;
+			bool hadOuterMethodColoring = false;
+			int lastOpenBrace = -1;
+			int lastCloseBrace = -1;
+
+			int commentLineStart = -1;
+			int commentStart = -1;
+			bool lineIsComment = false;
+			bool lineHasNonComment = false;
 
 			for (int checkPos = foundBlockStartIdx; true; checkPos++)
 			{
@@ -2162,19 +2192,62 @@ namespace IDE.ui
 
 				char8 checkC = mData.mText[checkPos].mChar;
 				if (checkC == '\n')
+				{
+					prevLineEnd = checkPos;
 					lastCrPos = checkPos;
+					if (!lineIsComment)
+					{
+						commentStart = -1;
+						commentLineStart = -1;
+					}
+					lineIsComment = false;
+					lineHasNonComment = false;
+				}
 
 				if (checkC.IsWhiteSpace)
 					continue;
 
 				let displayType = (SourceElementType)mData.mText[checkPos].mDisplayTypeId;
 				if (displayType == .Comment)
+				{
+					if (!lineHasNonComment)
+					{
+						if (commentStart == -1)
+							commentStart = checkPos;
+						if (commentLineStart == -1)
+							commentLineStart = prevLineEnd + 1;
+						lineIsComment = true;
+					}
 					continue;
+				}
+
+				lineHasNonComment = true;
+				lineIsComment = false;
+
+				if (innerBraceCount > 0)
+				{
+					if (checkC == '{')
+					{
+						innerBraceCount++;
+						braceCount++;
+					}
+					if (checkC == '}')
+					{
+						lastNonWS = checkPos;
+						innerBraceCount--;
+						braceCount--;
+					}
+
+					if (innerBraceCount > 0)
+						continue;
+				}
 
 				if (displayType == .Normal)
 				{
 					if (checkC == '(')
+					{
 						parenCount++;
+					}
 					else if (checkC == ')')
 						parenCount--;
 				}
@@ -2182,40 +2255,116 @@ namespace IDE.ui
 				if (parenCount != 0)
 					continue;
 
+				if (displayType == .Method)
+					hadOuterMethodColoring = true;
+
 				if ((displayType == .Normal) &&
 					((checkC == '{') || (checkC == '}') || (checkC == ';')))
 				{
-					if ((checkPos >= checkIdx) && (!expectingStatement))
+					if (checkC == '{')
+					{
+						lastOpenBrace = checkPos;
+						braceCount++;
+					}
+					if (checkC == '}')
 					{
+						lastCloseBrace = checkPos;
+						braceCount--;
+					}
+
+					if ((checkPos >= startCheckPos) && (!expectingStatement))
+					{
+						if (checkC == '{')
+						{
+							if (hadOuterMethodColoring)
+								statementKind = .Method;
+
+							if ((flags.HasFlag(.IncludeBlock)) || (statementKind == .Method))
+							{
+								innerBraceCount++;
+								continue;
+							}
+						}
+
 						endChar = checkC;
-						if (lastNonWS < checkIdx)
-							return false;
+						if (lastNonWS < startCheckPos)
+							return .None;
 
 						startIdx = stmtStart;
-						endIdx = lastNonWS + 1;
-						return true;
+						if ((stmtCommentStart != -1) && (stmtCommentStart < startIdx))
+							startIdx = stmtCommentStart;
+
+						if (checkC == '{')
+							endIdx = lastNonWS + 1;
+						else
+							endIdx = checkPos + 1;
+						return statementKind;
 					}
 
 					expectingStatement = true;
+					hadOuterMethodColoring = false;
 				}
 				else if (expectingStatement)
 				{
-					if (lastCrPos >= checkIdx)
+					if (lastCrPos >= startCheckPos)
 					{
-						return false;
+						if ((commentLineStart == -1) || (commentLineStart > startCheckPos))
+							break;
 					}
 
 					expectingStatement = false;
 					stmtStart = checkPos;
+					stmtCommentStart = commentStart;
 				}
 
 				lastNonWS = checkPos;
+				commentStart = -1;
 			}
 
-			return false;
+			if (!flags.HasFlag(.AllowInnerMethodSelect))
+				return .None;
+			
+			// If out starting pos is within a method then select the whole thing
+			if ((startCheckPos >= lastOpenBrace) && (startCheckPos <= lastCloseBrace) && (braceCount != 0))
+			{
+				let checkStmtKind = GetStatementRange(Math.Max(lastOpenBrace - 1, 0), .None, var checkStartIdx, var checkEndIdx, var checkEndChar);
+				//if ((checkStmtKind == .Method) && (startCheckPos >= checkStartIdx) && (startCheckPos <= checkEndIdx))
+				if (checkStmtKind == .Method)
+				{
+					startIdx = checkStartIdx;
+					endIdx = checkEndIdx;
+					endChar = checkEndChar;
+					return checkStmtKind;
+				}
+			}
+			return .None;
+		}
+
+		bool LineIsComment(int lineNum)
+		{
+			if (lineNum >= GetLineCount())
+				return false;
+
+			GetLinePosition(lineNum, var lineStart, var lineEnd);
+
+			bool lineIsComment = false;
+			for (int checkPos = lineStart; checkPos < lineEnd; checkPos++)
+			{
+				char8 checkC = mData.mText[checkPos].mChar;
+				if (checkC.IsWhiteSpace)
+					continue;
+
+				let displayType = (SourceElementType)mData.mText[checkPos].mDisplayTypeId;
+				if (displayType != .Comment)
+					return false;
+				
+				lineIsComment = true;
+			}
+
+			return lineIsComment;
 		}
 
-		void MoveSelection(int toLinePos)
+		void MoveSelection(int toLinePos, bool isStatementAware)
 		{
 			/*if (GetStatementRange(CursorTextPos, var startIdx, var endIdx))
 			{
@@ -2246,62 +2395,58 @@ namespace IDE.ui
 			String offsetText = scope .();
 			ExtractString(offsetLineStart, offsetLineEnd - offsetLineStart, offsetText);
 
-			if (movingDown)
+			if (isStatementAware)
 			{
-				GetLinePosition(Math.Max(offsetLinePos - 1, 0), var toLineStart, var toLineEnd);
-				String txt = scope .();
-				ExtractString(toLineStart, toLineEnd - toLineStart, txt);
-				if (GetStatementRange(toLineStart, var stmtStartIdx, var stmtEndIdx, var stmtEndChar))
+				if (movingDown)
 				{
-					String stmt = scope .();
-					ExtractString(stmtStartIdx, stmtEndIdx - stmtStartIdx, stmt);
-					GetLineCharAtIdx(stmtEndIdx - 1, var stmtLine, var stmtLineChar);
-					offsetLinePos = stmtLine + 1;
-					GetLinePosition(Math.Max(offsetLinePos, 0), out offsetLineStart, out offsetLineEnd);
-
-					if (stmtEndChar == '{')
-						offsetLinePos++;
+					GetLinePosition(Math.Max(offsetLinePos - 1, 0), var toLineStart, var toLineEnd);
+					String txt = scope .();
+					ExtractString(toLineStart, toLineEnd - toLineStart, txt);
+					if (GetStatementRange(toLineStart, .None, var stmtStartIdx, var stmtEndIdx, var stmtEndChar) != .None)
+					{
+						String stmt = scope .();
+						ExtractString(stmtStartIdx, stmtEndIdx - stmtStartIdx, stmt);
+						GetLineCharAtIdx(stmtEndIdx - 1, var stmtLine, var stmtLineChar);
+						offsetLinePos = stmtLine + 1;
+						GetLinePosition(Math.Max(offsetLinePos, 0), out offsetLineStart, out offsetLineEnd);
+
+						if (stmtEndChar == '{')
+							offsetLinePos++;
+					}
+					else if (GetStatementRange(toLineStart, .AllowInnerMethodSelect, var stmtStartIdx, var stmtEndIdx, var stmtEndChar) == .Method)
+					{
+						if (stmtStartIdx <= toLineStart)
+						{
+							GetLineCharAtIdx(stmtEndIdx, var endLine, var endChar);
+							//if (offsetLinePos)
+							offsetLinePos = endLine + 1;
+						}
+					}
 				}
-			}
-			else
-			{
-				/*for (int checkPos = offsetLineStart; checkPos < offsetLineEnd; checkPos++)
+				else
 				{
-					if (mData.mText[checkPos].mDisplayTypeId != 0)
-						continue;
-					char8 checkC = mData.mText[checkPos].mChar;
-					if (checkC.IsWhiteSpace)
-						continue;
-					if (checkC == '{')
+					GetLinePosition(Math.Max(offsetLinePos, 0), var toLineStart, var toLineEnd);
+					String txt = scope .();
+					ExtractString(toLineStart, toLineEnd - toLineStart, txt);
+
+					if (GetStatementRange(toLineStart, .None, var stmtStartIdx, var stmtEndIdx, var stmtEndChar) == .None)
 					{
-						if (offsetLinePos > prevCursorLineAndColumn.mLine)
-							offsetLinePos--;
+						if (stmtEndChar == '{')
+							GetLinePosition(Math.Max(offsetLinePos - 1, 0), out toLineStart, out toLineEnd);
 					}
-					break;
-				}*/
-
-				GetLinePosition(Math.Max(offsetLinePos, 0), var toLineStart, var toLineEnd);
-				String txt = scope .();
-				ExtractString(toLineStart, toLineEnd - toLineStart, txt);
-
-				if (!GetStatementRange(toLineStart, var stmtStartIdx, var stmtEndIdx, var stmtEndChar))
-				{
-					if (stmtEndChar == '{')
-						GetLinePosition(Math.Max(offsetLinePos - 1, 0), out toLineStart, out toLineEnd);
-				}
 
-				if (GetStatementRange(toLineStart, var stmtStartIdx, var stmtEndIdx, var stmtEndChar))
-				{
-					String stmt = scope .();
-					ExtractString(stmtStartIdx, stmtEndIdx - stmtStartIdx, stmt);
-					GetLineCharAtIdx(stmtStartIdx, var stmtLine, var stmtLineChar);
-					offsetLinePos = stmtLine;
-					GetLinePosition(Math.Max(offsetLinePos, 0), out offsetLineStart, out offsetLineEnd);
+					if (GetStatementRange(toLineStart, .AllowInnerMethodSelect, var stmtStartIdx, var stmtEndIdx, var stmtEndChar) != .None)
+					{
+						String stmt = scope .();
+						ExtractString(stmtStartIdx, stmtEndIdx - stmtStartIdx, stmt);
+						GetLineCharAtIdx(stmtStartIdx, var stmtLine, var stmtLineChar);
+						offsetLinePos = stmtLine;
+						GetLinePosition(Math.Max(offsetLinePos, 0), out offsetLineStart, out offsetLineEnd);
+					}
 				}
 			}
 
-
-			let wantCursorPos = LineAndColumn(Math.Max(offsetLinePos, 0), 0);
+			var wantCursorPos = LineAndColumn(Math.Max(offsetLinePos, 0), 0);
 			if (wantCursorPos.mLine >= GetLineCount())
 			{
 				CursorTextPos = mData.mTextLength;
@@ -2309,6 +2454,19 @@ namespace IDE.ui
 			}
 
 			CursorLineAndColumn = wantCursorPos;
+
+			String txt = scope .();
+			ExtractLine(offsetLinePos, txt);
+
+			if ((isStatementAware) && (LineIsComment(offsetLinePos - 1)))
+			{
+				if (movingDown)
+				{
+					InsertAtCursor("\n");
+					wantCursorPos.mLine++;
+				}
+			}
+
 			PasteText(str, "line");
 			CursorLineAndColumn = LineAndColumn(wantCursorPos.mLine, prevCursorLineAndColumn.mColumn);
 
@@ -2320,60 +2478,25 @@ namespace IDE.ui
 			int lineNum = CursorLineAndColumn.mLine;
 			GetLinePosition(lineNum, var lineStart, var lineEnd);
 			mSelection = .(lineStart, Math.Min(lineEnd + 1, mData.mTextLength));
-			MoveSelection(lineNum + (int)dir);
+			MoveSelection(lineNum + (int)dir, false);
 		}
 
 		public void MoveStatement(VertDir dir)
 		{
 			int lineNum = CursorLineAndColumn.mLine;
+			int origLineNum = lineNum;
 			GetLinePosition(lineNum, var lineStart, var lineEnd);
 
-			int selStart = -1;
-			int selEnd = -1;
-			int parenDepth = 0;
-
-			int checkPos = lineStart;
-			for ( ; checkPos < mData.mTextLength - 1; checkPos++)
-			{
-				char8 checkC = mData.mText[checkPos].mChar;
-
-				if (selStart == -1)
-				{
-					if (checkC == '\n')
-						break; // Don't support moving empty lines
-				   	if (!checkC.IsWhiteSpace)
-					{
-						selStart = checkPos;
-					}
-				}
-
-				if (mData.mText[checkPos].mDisplayTypeId != 0)
-					continue;
-
-				if ((checkC == ';') && (parenDepth == 0))
-				{
-					selEnd = checkPos + 1;
-					break;
-				}
-
-				if (checkC == '{')
-				{
-					parenDepth++;
-				}
+			var stmtKind = GetStatementRange(lineStart, .IncludeBlock, var stmtStart, var stmtEnd, var endChar);
+			if (stmtKind == .None)
+				return;
 
-				if (checkC == '}')
-				{
-					parenDepth--;
-					if (parenDepth <= 0)
-					{
-						selEnd = checkPos + 1;
-						break;
-					}
-				}
-			}
+			GetLineCharAtIdx(stmtStart, var startLineNum, var startLineChar);
+			GetLinePosition(startLineNum, out lineStart, out lineEnd);
+			lineNum = startLineNum;
 
-			if (selEnd == -1)
-				return;
+			int checkPos = stmtEnd;
+			int selEnd = stmtEnd;
 
 			for ( ; checkPos < mData.mTextLength - 1; checkPos++)
 			{
@@ -2396,7 +2519,9 @@ namespace IDE.ui
 				GetLineCharAtIdx(selEnd, var line, var lineChar);
 				toLine = line;
 			}
-			MoveSelection(toLine);
+			MoveSelection(toLine, true);
+
+			CursorLineAndColumn = .(Math.Min(CursorLineAndColumn.mLine + (origLineNum - startLineNum), Math.Max(GetLineCount() - 1, 0)), CursorLineAndColumn.mColumn);
 
 			mData.mUndoManager.Add(undoBatchStart.mBatchEnd);
 		}