Ver código fonte

Formatting options

Brian Fiete 3 anos atrás
pai
commit
67329ac774

+ 33 - 8
BeefLibs/Beefy2D/src/widgets/EditWidget.bf

@@ -540,6 +540,7 @@ namespace Beefy.widgets
         public EditWidget mEditWidget;
                 
         public float mTabSize;
+		public bool	mWantsTabsAsSpaces;
         public float mCharWidth = -1;
 		public int32 mTabLength = 4;
         public uint8 mExtendDisplayFlags;
@@ -1267,7 +1268,9 @@ namespace Beefy.widgets
 					{
 		                int prevTabCount = (int)((textX + 0.5f) / mTabSize);
 		                int wantTabCount = (int)((cursorX + 0.5f) / mTabSize);
-		                int wantAddTabs = wantTabCount - prevTabCount;                                
+		                int wantAddTabs = 0;
+						if (!mWantsTabsAsSpaces)
+							wantAddTabs = wantTabCount - prevTabCount;                                
 		                if (wantAddTabs > 0)                
 		                    textX = wantTabCount * mTabSize + mTextInsets.mLeft;                
 
@@ -3209,6 +3212,14 @@ namespace Beefy.widgets
             mEditWidget.UpdateScrollbars();
         }
 
+		protected void GetTabString(String str, int tabCount = 1)
+		{
+			if (mWantsTabsAsSpaces)
+				str.Append(' ', mTabLength * tabCount);
+			else
+				str.Append('\t', tabCount);
+		}
+
         public void BlockIndentSelection(bool unIndent = false)
         {
 			if (CheckReadOnly())
@@ -3270,15 +3281,30 @@ namespace Beefy.widgets
                 }
                 else
                 {
-                    startAdjust++;
+					if (mWantsTabsAsSpaces)
+						startAdjust += mTabLength;
+					else
+						startAdjust++;
+						
                     for (int lineIdx = minLineIdx; lineIdx <= maxLineIdx; lineIdx++)
                     {
                         int lineStart;
                         int lineEnd;
                         GetLinePosition(lineIdx, out lineStart, out lineEnd);
                         lineStart += endAdjust;
-                        indentTextAction.mInsertCharList.Add(((int32)lineStart, '\t'));
-                        endAdjust++;
+						if (mWantsTabsAsSpaces)
+						{
+							for (int i < mTabLength)
+							{
+								indentTextAction.mInsertCharList.Add(((int32)lineStart, ' '));
+								endAdjust++;
+							}
+						}
+						else
+						{
+	                        indentTextAction.mInsertCharList.Add(((int32)lineStart, '\t'));
+	                        endAdjust++;
+						}
                     }
 
 					indentTextAction.Redo();
@@ -3413,17 +3439,16 @@ namespace Beefy.widgets
 						let prevSelection = mSelection.Value;
 						mSelection = null;
 						for (int32 i = 0; i < indentCount; i++)
-						    InsertAtCursor("\t");
+						    InsertAtCursor(GetTabString(.. scope .()));
 						GetLinePosition(minLineIdx, out lineStart, out lineEnd);
 						mSelection = EditSelection(prevSelection.mStartPos + indentCount, prevSelection.mEndPos + indentCount);
 					}
 					else
-						InsertAtCursor("\t");
+						InsertAtCursor(GetTabString(.. scope .()));
 				}
 				else
 				{
-					for (int32 i = 0; i < indentCount; i++)
-						InsertAtCursor("\t");
+					InsertAtCursor(GetTabString(.. scope .(), indentCount));
 				}
             }
         }

+ 4 - 2
IDE/src/Compiler/BfParser.bf

@@ -145,7 +145,8 @@ namespace IDE.Compiler
         static extern bool BfParser_Reduce(void* bfParser, void* bfPassInstance);
 
         [CallingConvention(.Stdcall), CLink]        
-        static extern char8* BfParser_Format(void* bfParser, int32 formatEnd, int32 formatStart, out int32* outCharMapping, int32 maxCol);
+        static extern char8* BfParser_Format(void* bfParser, int32 formatEnd, int32 formatStart, out int32* outCharMapping, int32 maxCol, int32 tabSize, bool wantsTabsAsSpaces,
+			bool indentCaseLabels);
 
         [CallingConvention(.Stdcall), CLink]
         static extern char8* BfParser_GetDebugExpressionAt(void* bfParser, int32 cursorIdx);
@@ -244,7 +245,8 @@ namespace IDE.Compiler
         {                                    
             int32* charMappingPtr;
             var maxCol = gApp.mSettings.mEditorSettings.mWrapCommentsAt;
-            var stringPtr = BfParser_Format(mNativeBfParser, (int32)formatStart, (int32)formatEnd, out charMappingPtr, maxCol);
+            var stringPtr = BfParser_Format(mNativeBfParser, (int32)formatStart, (int32)formatEnd, out charMappingPtr, maxCol,
+				gApp.mSettings.mEditorSettings.mTabSize, gApp.mSettings.mEditorSettings.mTabsOrSpaces == .Spaces, gApp.mSettings.mEditorSettings.mIndentCaseLabels);
             str.Append(stringPtr);
 
             charMapping = new int32[str.Length];

+ 25 - 4
IDE/src/Settings.bf

@@ -622,6 +622,12 @@ namespace IDE
 				BackupOnly
 			}
 
+			public enum TabsOrSpaces
+			{
+				Tabs,
+				Spaces
+			}
+
 			public List<String> mFonts = new .() ~ DeleteContainerAndItems!(_);
 			public float mFontSize = 12;
 			public AutoCompleteShowKind mAutoCompleteShowKind = .PanelIfVisible;
@@ -641,9 +647,13 @@ namespace IDE
 			public bool mShowLineNumbers = true;
 			public bool mFreeCursorMovement;
 			public FileRecoveryKind mEnableFileRecovery = .Yes;
-			public bool mFormatOnSave = false;
 			public bool mSyncWithWorkspacePanel = false;
 			public int32 mWrapCommentsAt = 0;
+			public bool mFormatOnSave = false;
+			public bool mIndentCaseLabels = false;
+			public bool mLeftAlignPreprocessor = true;
+			public TabsOrSpaces mTabsOrSpaces = .Tabs;
+			public int32 mTabSize = 4;
 
 			public void Serialize(StructuredData sd)
 			{
@@ -669,9 +679,13 @@ namespace IDE
 				sd.Add("ShowLineNumbers", mShowLineNumbers);
 				sd.Add("FreeCursorMovement", mFreeCursorMovement);
 				sd.Add("EnableFileRecovery", mEnableFileRecovery);
-				sd.Add("FormatOnSave", mFormatOnSave);
 				sd.Add("SyncWithWorkspacePanel", mSyncWithWorkspacePanel);
 				sd.Add("WrapCommentsAt", mWrapCommentsAt);
+				sd.Add("FormatOnSave", mFormatOnSave);
+				sd.Add("TabsOrSpaces", mTabsOrSpaces);
+				sd.Add("TabSize", mTabSize);
+				sd.Add("IndentCaseLabels", mIndentCaseLabels);
+				sd.Add("LeftAlignPreprocessor", mLeftAlignPreprocessor);
 			}
 
 			public void Deserialize(StructuredData sd)
@@ -701,9 +715,13 @@ namespace IDE
 				sd.Get("ShowLineNumbers", ref mShowLineNumbers);
 				sd.Get("FreeCursorMovement", ref mFreeCursorMovement);
 				sd.GetEnum<FileRecoveryKind>("EnableFileRecovery", ref mEnableFileRecovery);
-				sd.Get("FormatOnSave", ref mFormatOnSave);
 				sd.Get("SyncWithWorkspacePanel", ref mSyncWithWorkspacePanel);
 				sd.Get("WrapCommentsAt", ref mWrapCommentsAt);
+				sd.Get("FormatOnSave", ref mFormatOnSave);
+				sd.Get("TabsOrSpaces", ref mTabsOrSpaces);
+				sd.Get("TabSize", ref mTabSize);
+				sd.Get("IndentCaseLabels", ref mIndentCaseLabels);
+				sd.Get("LeftAlignPreprocessor", ref mLeftAlignPreprocessor);
 			}
 
 			public void SetDefaults()
@@ -717,6 +735,8 @@ namespace IDE
 
 			public void Apply()
 			{
+				mTabSize = Math.Clamp(mTabSize, 1, 16);
+
 				if (mSpellCheckEnabled)
 				{
 					if (gApp.mSpellChecker == null)
@@ -1197,6 +1217,7 @@ namespace IDE
 			gApp.mSettings.mEditorSettings.mFontSize = Math.Clamp(gApp.mSettings.mEditorSettings.mFontSize, 6.0f, 72.0f);
 
 			mUISettings.Apply();
+			mEditorSettings.Apply();
 
 			Font.ClearFontNameCache();
 			gApp.PhysSetScale(gApp.mSettings.mUISettings.mScale / 100.0f, true);
@@ -1205,7 +1226,7 @@ namespace IDE
 
 			mKeySettings.Apply();
 			mDebuggerSettings.Apply();
-			mEditorSettings.Apply();
+			
 
 			for (var window in gApp.mWindows)
 			{

+ 10 - 2
IDE/src/ui/SettingsDialog.bf

@@ -128,10 +128,18 @@ namespace IDE.ui
 			AddPropertiesItem(category, "Show Line Numbers", "mShowLineNumbers");
 			AddPropertiesItem(category, "Free Cursor Movement", "mFreeCursorMovement");
 			AddPropertiesItem(category, "Enable File Recovery", "mEnableFileRecovery");
-			AddPropertiesItem(category, "Format on Save", "mFormatOnSave");
 			AddPropertiesItem(category, "Sync with Workspace Panel", "mSyncWithWorkspacePanel");
-			AddPropertiesItem(category, "Wrap Comments at Column", "mWrapCommentsAt");
+			category.Open(true, true);
 
+			(category, propEntry) = AddPropertiesItem(root, "Formatting");
+			category.mIsBold = true;
+			category.mTextColor = Color.Mult(DarkTheme.COLOR_TEXT, cHeaderColor);
+			AddPropertiesItem(category, "Format on Save", "mFormatOnSave");
+			AddPropertiesItem(category, "Tabs or Spaces", "mTabsOrSpaces");
+			AddPropertiesItem(category, "Tab Size", "mTabSize");
+			AddPropertiesItem(category, "Wrap Comments at Column", "mWrapCommentsAt");
+			AddPropertiesItem(category, "Indent Case Labels", "mIndentCaseLabels");
+			AddPropertiesItem(category, "Left Align Preprocessor", "mLeftAlignPreprocessor");
 			category.Open(true, true);
 		}
 

+ 83 - 52
IDE/src/ui/SourceEditWidgetContent.bf

@@ -779,7 +779,9 @@ namespace IDE.ui
             SetFont(IDEApp.sApp.mCodeFont, true, true);
 			//SetFont(DarkTheme.sDarkTheme.mSmallFont, false, false);
 
-            mTabSize = mFont.GetWidth("    ");
+			mWantsTabsAsSpaces = gApp.mSettings.mEditorSettings.mTabsOrSpaces == .Spaces;
+			mTabLength = gApp.mSettings.mEditorSettings.mTabSize;
+            mTabSize = mFont.GetWidth(scope String(' ', gApp.mSettings.mEditorSettings.mTabSize));
             mTextColors = sTextColors;
             mExtendDisplayFlags = (uint8)(SourceElementFlags.SpellingError | SourceElementFlags.SymbolReference);
             mShowLineBottomPadding = 2;
@@ -793,7 +795,9 @@ namespace IDE.ui
 		public override void RehupScale(float oldScale, float newScale)
 		{
 			base.RehupScale(oldScale, newScale);
-			mTabSize = mFont.GetWidth("    ");
+			mWantsTabsAsSpaces = gApp.mSettings.mEditorSettings.mTabsOrSpaces == .Spaces;
+			mTabLength = gApp.mSettings.mEditorSettings.mTabSize;
+			mTabSize = mFont.GetWidth(scope String(' ', gApp.mSettings.mEditorSettings.mTabSize));
 		}
 
 		protected override EditWidgetContent.Data CreateEditData()
@@ -1244,7 +1248,7 @@ namespace IDE.ui
 					else if (c == ' ')
 						blockOpenSpaceCount++;
 					else if (c == '\t')
-						blockOpenSpaceCount += 4; // SpacesInTab
+						blockOpenSpaceCount += gApp.mSettings.mEditorSettings.mTabSize; // SpacesInTab
 					else
 					{
 						blockOpenSpaceCount = 0;
@@ -1332,7 +1336,7 @@ namespace IDE.ui
 			return spaceCount;
 		}
 
-		public int GetLineEndColumn(int line, bool openingBlock, bool force, bool ignoreLineText = false, bool insertingElseStmt = false, float* outWidth = null)
+		public int GetLineEndColumn(int line, bool openingBlock, bool force, bool ignoreLineText = false, bool insertingElseStmt = false, bool ignoreCaseExpr = false, float* outWidth = null)
 		{
 			String curLineStr = scope String();
 			GetLineText(line, curLineStr);
@@ -1404,6 +1408,8 @@ namespace IDE.ui
 			List<int32> ifCtlDepthStack = scope List<int32>();
 
 			bool keepBlockIndented = false;
+			bool inSwitchCaseBlock = false;
+			bool mayBeDefaultCase = false;
 			for (int checkIdx = foundBlockStartIdx + 1; checkIdx < endingPos; checkIdx++)
 			{
 				char8 c = mData.mText[checkIdx].mChar;
@@ -1427,6 +1433,14 @@ namespace IDE.ui
 					skippingLine = true;
 				}
 
+				if (mayBeDefaultCase)
+				{
+					if (c == ':')
+						inSwitchCaseBlock = true;
+					else if (!isWhitespace)
+						mayBeDefaultCase = false;
+				}
+
 				if ((inCaseExpr) && (c == ':') && (elementType == .Normal) && (parenDepth == 0))
 				{
 					inCaseExpr = false;
@@ -1499,9 +1513,12 @@ namespace IDE.ui
 						case "case":
 							if (parenDepth == 0)
 							{
-								caseStartPos = checkIdx - 4;
+								caseStartPos = checkIdx - gApp.mSettings.mEditorSettings.mTabSize;
 								inCaseExpr = true;
+								inSwitchCaseBlock = true;
 							}
+						case "default":
+							mayBeDefaultCase = true;
 						case "switch":
 							ifDepth = 0;
 						}
@@ -1725,9 +1742,12 @@ namespace IDE.ui
 			if ((openingBlock) && (!keepBlockIndented) && (parenDepth == 0))
 				extraTab = Math.Max(1, extraTab - 1);
 
+			if ((inSwitchCaseBlock) && (!ignoreCaseExpr) && (gApp.mSettings.mEditorSettings.mIndentCaseLabels))
+				extraTab++;
+
 			int wantSpaceCount = blockOpenSpaceCount;
 			//if (!openingBlock)
-				wantSpaceCount += extraTab * 4;
+				wantSpaceCount += extraTab * gApp.mSettings.mEditorSettings.mTabSize;
 
 			if (inCaseExprNextLine)
 				wantSpaceCount++;
@@ -1890,7 +1910,7 @@ namespace IDE.ui
 
 				int alignColumn = GetLineEndColumn(lineAndColumn.mLine, isBlock, true,  true);
 
-			    String linePrefix = scope String('\t', alignColumn / tabSpaceCount);
+			    String linePrefix = GetTabString(.. scope String(), alignColumn / tabSpaceCount);
 			    CursorLineAndColumn = LineAndColumn(lineAndColumn.mLine, alignColumn);
 
 				bool isFullSwitch = false;
@@ -2080,7 +2100,7 @@ namespace IDE.ui
 			float x;
 			float y;
 			float wantWidth = 0;
-			int column = GetLineEndColumn(line, false, false, false, false, &wantWidth);
+			int column = GetLineEndColumn(line, false, false, false, false, false, &wantWidth);
 			GetTextCoordAtLineAndColumn(line, column, out x, out y);
 			if (wantWidth != 0)
 				x = wantWidth + mTextInsets.mLeft;
@@ -2285,7 +2305,7 @@ namespace IDE.ui
 					}
                 }                 
 
-				int indentCount = GetLineEndColumn(minLineIdx, true, true, true) / 4;
+				int indentCount = GetLineEndColumn(minLineIdx, true, true, true) / gApp.mSettings.mEditorSettings.mTabSize;
 				bool wantsContentTab = indentCount == selectedIndentCount;
 				
                 /*if (mAllowVirtualCursor)
@@ -2339,25 +2359,39 @@ namespace IDE.ui
                     	lineStart += endAdjust;
 						lineEnd += endAdjust;
 					}
+
+					String tabStr = scope .();
+					GetTabString(tabStr);
+					int32 i = 0;
+
+					void AddTab()
+					{
+						InsertText(lineStart + i, tabStr);
+						for (var c in tabStr.RawChars)
+						{
+						    indentTextAction.mInsertCharList.Add(((int32)(lineStart + i), c));
+						    endAdjust++;
+							i++;
+						}
+					}
+
                     if (lineIdx == minLineIdx)
                     {
-                        int32 i;
-                        for (i = 0; i < indentCount; i++)
+                        for (int indentIdx < indentCount)
                         {
-                            InsertText(lineStart + i, "\t");
-                            indentTextAction.mInsertCharList.Add(((int32)(lineStart + i), '\t'));
-                            endAdjust++;
+                            AddTab();
                         }
 
                         newSel.mStartPos = (int32)(lineStart + i);
 
                         if (wantsContentTab)
                         {
-                            InsertText(lineStart + i, "{\n\t");
+                            InsertText(lineStart + i, "{\n");
                             indentTextAction.mInsertCharList.Add(((int32)(lineStart + i), '{'));
                             indentTextAction.mInsertCharList.Add(((int32)(lineStart + i + 1), '\n'));
-                            indentTextAction.mInsertCharList.Add(((int32)(lineStart + i + 2), '\t'));
-                            endAdjust += 3;
+							i += 2;
+                            endAdjust += 2;
+							AddTab();
                         }
                         else
                         {
@@ -2381,12 +2415,10 @@ namespace IDE.ui
 							lineStart++;
 						}
 
-                        int32 i;
-                        for (i = 0; i < indentCount; i++)
-                        {
-                            InsertText(lineStart + i, "\t");
-                            indentTextAction.mInsertCharList.Add(((int32)(lineStart + i), '\t'));
-                        }
+                        for (int indentIdx < indentCount)
+						{
+						    AddTab();
+						}
 
 						if (isEmbeddedEnd)
 						{
@@ -2409,9 +2441,7 @@ namespace IDE.ui
 							char8 c = mData.mText[lineStart].mChar;
 							if (c != '#')
 							{
-		                        InsertText(lineStart, "\t");
-		                        indentTextAction.mInsertCharList.Add(((int32)(lineStart), '\t'));
-		                        endAdjust++;
+		                        AddTab();
 							}
 						}
                     }                    
@@ -2465,7 +2495,7 @@ namespace IDE.ui
                         int column = GetLineEndColumn(lineIdx, true, false, true);
 
 						// If we're aligned with the previous line then do the 'block indent' logic, otherwise are are already indented
-						if (indentCount == column / 4)
+						if (indentCount == column / gApp.mSettings.mEditorSettings.mTabSize)
 						{
 							bool isExpr = false;
 							bool mayBeExpr = false;
@@ -2542,12 +2572,12 @@ namespace IDE.ui
 							if (isExpr)
 							{
 								// Lambda opening or initializer expression
-								column += 4;
+								column += gApp.mSettings.mEditorSettings.mTabSize;
 							}
 						}
 
                         CursorLineAndColumn = LineAndColumn(lineIdx, column);
-                        indentCount = column / 4;
+                        indentCount = column / gApp.mSettings.mEditorSettings.mTabSize;
                     }
 
                     if (lineIdx < GetLineCount() - 1)
@@ -2559,13 +2589,13 @@ namespace IDE.ui
                         for (int32 i = 0; i < nextLineText.Length; i++)
                         {
                             if (nextLineText[i] == '\t')
-                                spaceCount += 4;
+                                spaceCount += gApp.mSettings.mEditorSettings.mTabSize;
                             else if (nextLineText[i] == ' ')
                                 spaceCount++;
                             else
                                 break;                            
                         }
-                        if (spaceCount > indentCount * 4)
+                        if (spaceCount > indentCount * gApp.mSettings.mEditorSettings.mTabSize)
                         {
                             // Next line is indented? Just simple open
                             InsertAtCursor("{");
@@ -2581,15 +2611,14 @@ namespace IDE.ui
                         if ((lineText.Length > 0) && (String.IsNullOrWhiteSpace(lineText)))
                         {
                             ClearLine();
-                            CursorLineAndColumn = LineAndColumn(lineIdx, indentCount * 4);                
+                            CursorLineAndColumn = LineAndColumn(lineIdx, indentCount * gApp.mSettings.mEditorSettings.mTabSize);
                         }
 
                         // This will already insert at correct position
                         InsertAtCursor("{");
                         sb.Append("\n");
                         sb.Append("\n");
-                        for (int32 i = 0; i < indentCount; i++)
-                            sb.Append("\t");
+						GetTabString(sb, indentCount);
                         sb.Append("}");
                         InsertAtCursor(sb);
                     }
@@ -2607,11 +2636,9 @@ namespace IDE.ui
                         for (int i = lineText.Length; i < indentCount; i++)
                             sb.Append("\t");
                         sb.Append("{\n");
-                        for (int i = 0; i < indentCount; i++)
-                            sb.Append("\t");
+						GetTabString(sb, indentCount);
                         sb.Append("\t\n");
-                        for (int i = 0; i < indentCount; i++)
-                            sb.Append("\t");
+						GetTabString(sb, indentCount);
                         sb.Append("}");
                         InsertAtCursor(sb);
                     }
@@ -2771,7 +2798,7 @@ namespace IDE.ui
 					InsertAtCursor("*/");
 
 					if (doComment != null)
-						mSelection = EditSelection(firstCharPos, lastCharPos + 4);
+						mSelection = EditSelection(firstCharPos, lastCharPos + gApp.mSettings.mEditorSettings.mTabSize);
 				}
 
 				if (undoBatchStart != null)
@@ -2877,7 +2904,7 @@ namespace IDE.ui
 					continue;
 				}
 				if (c == '\t')
-					lineStartCol += 4;
+					lineStartCol += gApp.mSettings.mEditorSettings.mTabSize;
 				else if (c == ' ')
 					lineStartCol++;
 				else
@@ -2911,7 +2938,7 @@ namespace IDE.ui
 					commentNow = true;
 
 				if (c == '\t')
-					lineStartCol += 4;
+					lineStartCol += gApp.mSettings.mEditorSettings.mTabSize;
 				else if (c == ' ')
 					lineStartCol++;
 				else
@@ -2921,9 +2948,9 @@ namespace IDE.ui
 				{
 					CursorTextPos = i;
 					String str = scope .();
-					while (lineStartCol + 4 <= wantLineCol)
+					while (lineStartCol + gApp.mSettings.mEditorSettings.mTabSize <= wantLineCol)
 					{
-						lineStartCol += 4;
+						lineStartCol += gApp.mSettings.mEditorSettings.mTabSize;
 						str.Append("\t");
 					}
 					str.Append("//");
@@ -3927,13 +3954,13 @@ namespace IDE.ui
                         int column = GetLineEndColumn(line, isBlockOpen, true, true);
 						if (lineTextAtCursor.StartsWith("}"))
 						{
-							column -= 4; // SpacesInTab
+							column -= gApp.mSettings.mEditorSettings.mTabSize; // SpacesInTab
 						}
                         if (column > 0)
                         {
 							String tabStr = scope String();
-							tabStr.Append('\t', column / 4);
-							tabStr.Append(' ', column % 4);
+							tabStr.Append('\t', column / gApp.mSettings.mEditorSettings.mTabSize);
+							tabStr.Append(' ', column % gApp.mSettings.mEditorSettings.mTabSize);
                             InsertAtCursor(tabStr);
 						}
 
@@ -4076,7 +4103,7 @@ namespace IDE.ui
 								int closeLineChar;
 								GetLineCharAtIdx(checkPos, out closeLine, out closeLineChar);
 
-								int expectedColumn = GetLineEndColumn(closeLine, true, true, true) - 4;
+								int expectedColumn = GetLineEndColumn(closeLine, true, true, true) - gApp.mSettings.mEditorSettings.mTabSize;
 								int actualColumn = GetActualLineStartColumn(closeLine);
 
 								if (expectedColumn == actualColumn)
@@ -4145,7 +4172,7 @@ namespace IDE.ui
                     String lineText = scope String();
                     GetLineText(line, lineText);
                     lineText.Trim();
-                    if ((lineText.Length == 0) && (mAllowVirtualCursor))
+                    if ((lineText.Length == 0) && (mAllowVirtualCursor) && (gApp.mSettings.mEditorSettings.mLeftAlignPreprocessor))
                         CursorLineAndColumn = LineAndColumn(line, 0);
                     doChar = true;
                 }
@@ -4162,7 +4189,7 @@ namespace IDE.ui
                     if (lineText.Length == 0)
                     {
                         ClearLine();
-                        CursorLineAndColumn = LineAndColumn(line, Math.Max(0, GetLineEndColumn(line, false, false) - 4));
+                        CursorLineAndColumn = LineAndColumn(line, Math.Max(0, GetLineEndColumn(line, false, false) - gApp.mSettings.mEditorSettings.mTabSize));
                         CursorMoved();
                     }
                     base.KeyChar(keyChar);
@@ -4282,7 +4309,11 @@ namespace IDE.ui
 							if ((isLabel) && (trimmedLineText != "default:"))
 								wantLineColumn = GetLineEndColumn(line, true, true, true);
 							else
-                            	wantLineColumn = GetLineEndColumn(line, false, true, true) - 4;
+							{
+                            	wantLineColumn = GetLineEndColumn(line, false, true, true, false, true);
+								if (!gApp.mSettings.mEditorSettings.mIndentCaseLabels)
+									wantLineColumn -= gApp.mSettings.mEditorSettings.mTabSize;
+							}
 						}
 
                         // Move "case" back to be inline with switch statement
@@ -4291,7 +4322,7 @@ namespace IDE.ui
 	                        String tabStartStr = scope String();
 	                        tabStartStr.Append(lineText, 0, lineChar - trimmedLineText.Length);
 	                        int32 columnPos = (int32)(GetTabbedWidth(tabStartStr, 0) / mCharWidth + 0.001f);
-	                        if (columnPos >= wantLineColumn + 4)
+	                        if (columnPos >= wantLineColumn + gApp.mSettings.mEditorSettings.mTabSize)
 	                        {
 	                            mSelection = EditSelection();
 	                            mSelection.ValueRef.mEndPos = (int32)(cursorTextIdx - trimmedLineText.Length);
@@ -5193,7 +5224,7 @@ namespace IDE.ui
 			GetCursorLineChar(out line, out lineChar);            
 			
 			float wantWidth = 0;
-			int virtualEnd = GetLineEndColumn(line, false, false, false, false, &wantWidth);
+			int virtualEnd = GetLineEndColumn(line, false, false, false, false, false, &wantWidth);
 
 			String curLineStr = scope String();
 			GetLineText(line, curLineStr);

+ 2 - 1
IDE/src/ui/SourceViewPanel.bf

@@ -6873,7 +6873,8 @@ namespace IDE.ui
 									{
 										int idx = embedEWC.GetTextIdx(mQueuedEmitShowData.mLine, mQueuedEmitShowData.mColumn);
 										emitEmbed.mView.mSourceViewPanel.FocusEdit();
-										emitEmbed.mView.mSourceViewPanel.ShowFileLocation(idx, .Always);
+										if (idx >= 0)
+											emitEmbed.mView.mSourceViewPanel.ShowFileLocation(idx, .Always);
 										DeleteAndNullify!(mQueuedEmitShowData);
 									}
 								}

+ 5 - 1
IDEHelper/Compiler/BfParser.cpp

@@ -3940,7 +3940,8 @@ BF_EXPORT bool BF_CALLTYPE BfParser_Reduce(BfParser* bfParser, BfPassInstance* b
 }
 
 static Array<int> gCharMapping;
-BF_EXPORT const char* BF_CALLTYPE BfParser_Format(BfParser* bfParser, int formatStart, int formatEnd, int** outCharMapping, int maxCol)
+BF_EXPORT const char* BF_CALLTYPE BfParser_Format(BfParser* bfParser, int formatStart, int formatEnd, int** outCharMapping, int maxCol, int tabSize, bool wantsTabsAsSpaces,
+	bool indentCaseLabels)
 {
 	BP_ZONE("BfParser_Reduce");
 	String& outString = *gTLStrReturn.Get();
@@ -3948,6 +3949,9 @@ BF_EXPORT const char* BF_CALLTYPE BfParser_Format(BfParser* bfParser, int format
 	gCharMapping.Clear();
 	BfPrinter bfPrinter(bfParser->mRootNode, bfParser->mSidechannelRootNode, bfParser->mErrorRootNode);
 	bfPrinter.mMaxCol = maxCol;
+	bfPrinter.mTabSize = tabSize;
+	bfPrinter.mWantsTabsAsSpaces = wantsTabsAsSpaces;
+	bfPrinter.mIndentCaseLabels = indentCaseLabels;
 	bfPrinter.mFormatStart = formatStart;
 	bfPrinter.mFormatEnd = formatEnd;
 	bfPrinter.mCharMapping = &gCharMapping;

+ 28 - 24
IDEHelper/Compiler/BfPrinter.cpp

@@ -45,6 +45,9 @@ BfPrinter::BfPrinter(BfRootNode *rootNode, BfRootNode *sidechannelRootNode, BfRo
 	mCurTypeDecl = NULL;
 	mCurCol = 0;
 	mMaxCol = 120;
+	mTabSize = 4;
+	mWantsTabsAsSpaces = false;
+	mIndentCaseLabels = false;
 }
 
 void BfPrinter::Write(const StringView& str)
@@ -59,7 +62,7 @@ void BfPrinter::Write(const StringView& str)
 		{
 			char c = str[i];
 			if (c == '\t')
-				mCurCol = ((mCurCol + 1) & ~3) + 4;			
+				mCurCol = ((mCurCol / mTabSize) + 1) * mTabSize;
 			else
 				mCurCol++;
 		}	
@@ -114,10 +117,10 @@ void BfPrinter::Write(const StringView& str)
 
 void BfPrinter::FlushIndent()
 {	
-	while (mQueuedSpaceCount >= 4)
+	while ((mQueuedSpaceCount >= mTabSize) && (!mWantsTabsAsSpaces))
 	{
 		Write("\t");
-		mQueuedSpaceCount -= 4;
+		mQueuedSpaceCount -= mTabSize;
 	}
 
 	while (mQueuedSpaceCount > 0)
@@ -141,15 +144,10 @@ void BfPrinter::Write(BfAstNode* node, int start, int len)
 		{
 			char c = parserData->mSrc[start + i];
 			if (c == '\t')
-				mCurCol = ((mCurCol + 1) & ~3) + 4;
+				mCurCol = ((mCurCol / mTabSize) + 1) * mTabSize;
 			else
 				mCurCol++;
-		}
-
- 		if ((mCurCol > mMaxCol) && (startCol != 0))
- 		{
-			NOP;
- 		}
+		} 		
 	}
 
 	mOutString.Append(node->GetSourceData()->mSrc + start, len);
@@ -287,7 +285,7 @@ int BfPrinter::CalcOrigLineSpacing(BfAstNode* bfAstNode, int* lineStartIdx)
 		if (c == '\n')
 			break;
 		if (c == '\t')
-			origLineSpacing += 4;
+			origLineSpacing += mTabSize;
 		else if (c == ' ')
 			origLineSpacing += 1;
 		else
@@ -539,7 +537,7 @@ void BfPrinter::WriteIgnoredNode(BfAstNode* node)
 			}
 			else if (c == '\t')
 			{
-				mQueuedSpaceCount += 4;
+				mQueuedSpaceCount += mTabSize;
 				emitChar = false;
 			}
 			else
@@ -548,7 +546,7 @@ void BfPrinter::WriteIgnoredNode(BfAstNode* node)
 				if ((c != '#') || (mQueuedSpaceCount > 0))
 					mQueuedSpaceCount = std::max(0, mQueuedSpaceCount + mLastSpaceOffset);
 				else
-					mQueuedSpaceCount = mCurIndentLevel * 4; // Do default indent
+					mQueuedSpaceCount = mCurIndentLevel * mTabSize; // Do default indent
 				isNewLine = false;				
 			}
 		}
@@ -581,7 +579,7 @@ void BfPrinter::WriteIgnoredNode(BfAstNode* node)
 				if ((mCurCol + len > mMaxCol) && (lineEmittedChars >= 8))
 				{
 					Write("\n");
-					mQueuedSpaceCount = mCurIndentLevel * 4;
+					mQueuedSpaceCount = mCurIndentLevel * mTabSize;
 					FlushIndent();
 
 					if (isStarredBlockComment)
@@ -674,7 +672,7 @@ void BfPrinter::CheckRawNode(BfAstNode* node)
 		{
 			ExpectSpace();
 			if (inLineStart)
-				spaceCount += 4;
+				spaceCount += mTabSize;
 		}
 		else if (c == ' ')
 		{
@@ -690,7 +688,7 @@ void BfPrinter::CheckRawNode(BfAstNode* node)
 
 	if ((spaceCount > 0) && (mCurBlockState != NULL))
 	{
-		int indentCount = spaceCount / 4;
+		int indentCount = spaceCount / mTabSize;
 		mNextStateModify.mWantVirtualIndent = BF_MAX(indentCount, mCurBlockState->mIndentStart + 1);
 	}
 }
@@ -765,11 +763,11 @@ void BfPrinter::Visit(BfAstNode* bfAstNode)
 			if (c == ' ')
 				prevSpaceCount++;
 			else if (c == '\t')
-				prevSpaceCount += 4;
+				prevSpaceCount += mTabSize;
 			else if (c == '\n')
 			{
 				// Found previous line
-				mCurIndentLevel = prevSpaceCount / 4;
+				mCurIndentLevel = prevSpaceCount / mTabSize;
 				break;
 			}
 			else
@@ -819,11 +817,11 @@ void BfPrinter::Visit(BfAstNode* bfAstNode)
 					if (c == ' ')
 						spaceCount++;
 					else if (c == '\t')
-						spaceCount += 4;
+						spaceCount += mTabSize;
 
 					if (((c == '\n') || (i == bfAstNode->GetSrcStart() - 1)) && (hadPrevLineSpacing) && (prevSpaceCount > 0))
 					{							
-						mQueuedSpaceCount += std::max(0, spaceCount - prevSpaceCount) - std::max(0, indentOffset * 4);
+						mQueuedSpaceCount += std::max(0, spaceCount - prevSpaceCount) - std::max(0, indentOffset * mTabSize);
 						
 						prevSpaceCount = -1;
 						hadPrevLineSpacing = false;
@@ -840,18 +838,18 @@ void BfPrinter::Visit(BfAstNode* bfAstNode)
 							if (c == ' ')
 								prevSpaceCount++;
 							else if (c == '\t')
-								prevSpaceCount += 4;
+								prevSpaceCount += mTabSize;
 							
 							if ((c == '\n') || (backIdx == 0))
 							{
 								// Found previous line
 								usedTrivia = true;
 								Write("\n");
-								mQueuedSpaceCount = mCurIndentLevel * 4;
+								mQueuedSpaceCount = mCurIndentLevel * mTabSize;
 
 								// Indents extra if we have a statement split over multiple lines
 								if (!mExpectingNewLine)
-									mQueuedSpaceCount += 4;
+									mQueuedSpaceCount += mTabSize;
 
 								break;
 							}
@@ -885,7 +883,7 @@ void BfPrinter::Visit(BfAstNode* bfAstNode)
 					if (!isspace((uint8)c))
 					{
 						Write("\n");
-						mQueuedSpaceCount = mCurIndentLevel * 4;
+						mQueuedSpaceCount = mCurIndentLevel * mTabSize;
 						if (!mNextStateModify.mDoingBlockClose)
 						{
 							int origLineSpacing = CalcOrigLineSpacing(bfAstNode, NULL);
@@ -1958,6 +1956,9 @@ void BfPrinter::Visit(BfCaseExpression* caseExpr)
 
 void BfPrinter::Visit(BfSwitchCase* switchCase)
 {
+	if (mIndentCaseLabels)
+		ExpectIndent();
+
 	VisitChild(switchCase->mCaseToken);	
 	for (int caseIdx = 0; caseIdx < (int) switchCase->mCaseExpressions.size(); caseIdx++)
 	{
@@ -1979,6 +1980,9 @@ void BfPrinter::Visit(BfSwitchCase* switchCase)
 		VisitChild(switchCase->mEndingSemicolonToken);
 		ExpectNewLine();
 	}
+
+	if (mIndentCaseLabels)
+		ExpectUnindent();
 }
 
 void BfPrinter::Visit(BfWhenExpression* whenExpr)

+ 3 - 0
IDEHelper/Compiler/BfPrinter.h

@@ -79,6 +79,9 @@ public:
 	bool mExpectingNewLine;
 	int mCurCol;
 	int mMaxCol;
+	int mTabSize;
+	bool mWantsTabsAsSpaces;
+	bool mIndentCaseLabels;
 
 	bool mIsFirstStatementInBlock;
 	bool mForceUseTrivia;