Skip to content

Commit 6bf85b7

Browse files
authored
Replace spaces with dashes when naming branches (jorio#88)
1 parent afa163c commit 6bf85b7

5 files changed

Lines changed: 58 additions & 2 deletions

File tree

gitfourchette/forms/newbranchdialog.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def __init__(
5959

6060
self.ui.nameEdit.setFocus()
6161
self.ui.nameEdit.selectAll()
62+
self.ui.nameEdit.setValidator(ReplaceSpacesWithDashes())
6263
self.preSelectLeaf(self.ui.nameEdit)
6364

6465
@property

gitfourchette/tasks/branchtasks.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def flow(self, oldBranchName: str):
9292
subtitle=_("Current name: {0}", oldBranchName))
9393
dlg.setText(oldBranchName)
9494
dlg.setValidator(lambda name: nameValidationMessage(name, forbiddenBranchNames, nameTaken))
95+
dlg.lineEdit.setValidator(ReplaceSpacesWithDashes())
9596
dlg.okButton.setText(_("Rename"))
9697

9798
# Pre-select leaf name (e.g. in "folder/leaf" select only "leaf")
@@ -159,6 +160,7 @@ def validate(newFolderName: str) -> str:
159160
dlg.setValidator(validate)
160161
dlg.okButton.setText(_("Rename"))
161162
dlg.lineEdit.setPlaceholderText(_("Leave blank to move the branches to the root folder."))
163+
dlg.lineEdit.setValidator(ReplaceSpacesWithDashes())
162164

163165
yield from self.flowDialog(dlg)
164166
dlg.deleteLater()

gitfourchette/toolbox/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,4 @@
9898
)
9999
from .urltooltip import UrlToolTip
100100
from .validatormultiplexer import ValidatorMultiplexer
101+
from .validators import ReplaceSpacesWithDashes
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# -----------------------------------------------------------------------------
2+
# Copyright (C) 2025 Iliyas Jorio.
3+
# This file is part of GitFourchette, distributed under the GNU GPL v3.
4+
# For full terms, see the included LICENSE file.
5+
# -----------------------------------------------------------------------------
6+
7+
from gitfourchette.qt import QValidator
8+
9+
10+
class ReplaceSpacesWithDashes(QValidator):
11+
def validate(self, text: str, pos: int) -> tuple[QValidator.State, str, int]:
12+
text = text.replace(" ", "-")
13+
return QValidator.State.Acceptable, text, pos

test/test_tasks_branch.py

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,29 @@ def testNewBranch(tempDir, mainWindow, method, switch):
5959
assert repo.head_branch_shorthand == 'master'
6060

6161

62+
def testNewBranchNaming(tempDir, mainWindow):
63+
"""Test that spaces in branch names are automatically replaced with dashes"""
64+
wd = unpackRepo(tempDir)
65+
rw = mainWindow.openRepo(wd)
66+
sb = rw.sidebar
67+
repo = rw.repo
68+
69+
node = sb.findNodeByKind(SidebarItem.LocalBranchesHeader)
70+
menu = sb.makeNodeMenu(node)
71+
triggerMenuAction(menu, "new branch")
72+
73+
dlg: NewBranchDialog = findQDialog(rw, "new branch")
74+
nameEdit = dlg.ui.nameEdit
75+
76+
nameEdit.setText("hello branch")
77+
78+
assert nameEdit.text() == "hello-branch"
79+
80+
dlg.accept()
81+
82+
assert 'hello-branch' in repo.branches.local
83+
84+
6285
def testNewBranchThenSwitchBlockedByConflicts(tempDir, mainWindow):
6386
wd = unpackRepo(tempDir)
6487
reposcenario.statelessConflictingChange(wd)
@@ -182,13 +205,22 @@ def testRenameBranch(tempDir, mainWindow, method):
182205
"nope.lock", "nope/", "nope.",
183206
"nope/.nope", "nope//nope", "nope@{nope", "no..pe",
184207
".nope", "/nope",
185-
"no pe", "no~pe", "no^pe", "no:pe", "no[pe", "no?pe", "no*pe", "no\\pe",
208+
"no~pe", "no^pe", "no:pe", "no[pe", "no?pe", "no*pe", "no\\pe",
186209
"nul", "nope/nul", "nul/nope", "lpt3", "com2",
187210
]
211+
fixableNames = [
212+
# Illegal patterns that can be automatically fixed by the input field
213+
"no pe",
214+
]
188215
for bad in badNames:
189216
nameEdit.setText(bad)
190217
assert not okButton.isEnabled(), f"name shouldn't pass validation: {bad}"
191218
QTest.qWait(1) # go through ValidatorMultiplexer's tooltip code path for coverage
219+
for fixable in fixableNames:
220+
nameEdit.setText(fixable)
221+
nameEdit.textEdited.emit(fixable)
222+
assert okButton.isEnabled(), f"name should pass validation: {fixable}"
223+
QTest.qWait(1) # go through ValidatorMultiplexer's tooltip code path for coverage
192224

193225
nameEdit.setText("mainbranch")
194226
assert okButton.isEnabled()
@@ -305,13 +337,20 @@ def testRenameBranchFolder(tempDir, mainWindow, method, newName):
305337
"nope.lock", "nope/", "nope.",
306338
"nope/.nope", "nope//nope", "nope@{nope", "no..pe",
307339
".nope", "/nope",
308-
"no pe", "no~pe", "no^pe", "no:pe", "no[pe", "no?pe", "no*pe", "no\\pe",
340+
"no~pe", "no^pe", "no:pe", "no[pe", "no?pe", "no*pe", "no\\pe",
309341
"nul", "nope/nul", "nul/nope", "lpt3", "com2",
310342
]
343+
fixableNames = [
344+
# Illegal patterns that can be automatically fixed by the input field
345+
"no pe",
346+
]
311347
for bad in badNames:
312348
nameEdit.setText(bad)
313349
assert not okButton.isEnabled(), f"name shouldn't pass validation: {bad}"
314350
print(bad, "-->", nameEdit.actions()[0].toolTip())
351+
for fixable in fixableNames:
352+
nameEdit.setText(fixable)
353+
assert okButton.isEnabled(), f"name should pass validation: {fixable}"
315354

316355
nameEdit.setText(newName)
317356
assert okButton.isEnabled()

0 commit comments

Comments
 (0)