Skip to content

Commit 4ef03ed

Browse files
committed
Fix opening files that have special chars like '$' in filename
This fixes a whole host of related issues in MacVim that fails to properly sanitize filenames when opening files using the GUI (e.g. drag-and-drop, file type associations, etc). The core issue came from the fact that the code used to rely on constructing Vimscript commands to send to code Vim to parse using `addInput` (e.g. `:tabe <filename>`). This was convenient and fast to add new feature but requires properly sanitizing filenames (since that's an arbitrary user input). It used a bespoke function `stringByEscapingSpecialFilenameCharacters` but it didn't fully work ('$' would not be escaped so it would be interpreted as a Vim variable) for all filenames. One solution should be to use Vim's fnameescape() utility, but it doesn't fully solve all edge cases. For example, if we hae a newline in a filename (which is admittedly weird) it will still break the Vimscript parsing. Better solution is to simply construct the raw Ex commands in C manually. It forces more tie-in to Vim's internals but is the most robust way to arbitary filenames. Replace all usage of stringByEscapingSpecialFilenameCharacters with this method: * `handleOpenWithArguments:` is used by drag-and-drop and opening files from GUI, so fix that to construct Vim function calls. Also fixes some weird bugs in existing behavior (e.g. if you drag multiple files in but one of them is opened alrady, it used to choose the wrong tab to do the `sall` split in. Now just make sure to make a new tab). * Dragging files to tab bars. MacVim has a special behavior where dragging files to tab bars will open files in that particular tab. Consolidate the behavior to use `handleOpenWithArguments` as well. Also fix an issue where previously it would forcefully stomp whatever buffer you had in that tab even if it had unsaved changes. * Misc cases: New File Here macOS service and a "open first file if exists already" functionality also need to be fixed. For these two cases, make new MMBackend handlers just for simplicity as they aren't doing anything complicated. For future TODO: - Implement tests for this when new testing infrastructure is up for testing MacVim-specific functionality. Fix #863.
1 parent 651ad8e commit 4ef03ed

7 files changed

Lines changed: 399 additions & 122 deletions

File tree

src/MacVim/MMAppController.m

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -976,21 +976,11 @@ - (BOOL)openFiles:(NSArray *)filenames withArguments:(NSDictionary *)args
976976
//
977977
// NOTE: Raise window before passing arguments, otherwise the
978978
// selection will be lost when selectionRange is set.
979-
firstFile = [firstFile stringByEscapingSpecialFilenameCharacters];
980-
981-
NSString *bufCmd = @"tab sb";
982-
switch (layout) {
983-
case MMLayoutHorizontalSplit: bufCmd = @"sb"; break;
984-
case MMLayoutVerticalSplit: bufCmd = @"vert sb"; break;
985-
case MMLayoutArglist: bufCmd = @"b"; break;
986-
}
987-
988-
NSString *input = [NSString stringWithFormat:@"<C-\\><C-N>"
989-
":let oldswb=&swb|let &swb=\"useopen,usetab\"|"
990-
"%@ %@|let &swb=oldswb|unl oldswb|"
991-
"cal foreground()<CR>", bufCmd, firstFile];
992-
993-
[vc addVimInput:input];
979+
NSDictionary *args = [NSDictionary dictionaryWithObjectsAndKeys:
980+
firstFile, @"filename",
981+
[NSNumber numberWithInt:layout], @"layout",
982+
nil];
983+
[vc sendMessage:SelectAndFocusOpenedFileMsgID data:[args dictionaryAsData]];
994984
}
995985

996986
[vc passArguments:arguments];
@@ -1465,16 +1455,15 @@ - (void)newFileHere:(NSPasteboard *)pboard userData:(NSString *)userData
14651455
if (!dirIndicator)
14661456
path = [path stringByDeletingLastPathComponent];
14671457

1468-
path = [path stringByEscapingSpecialFilenameCharacters];
1469-
14701458
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
14711459
BOOL openInCurrentWindow = [ud boolForKey:MMOpenInCurrentWindowKey];
14721460
MMVimController *vc;
14731461

14741462
if (openInCurrentWindow && (vc = [self topmostVimController])) {
1475-
NSString *input = [NSString stringWithFormat:@"<C-\\><C-N>"
1476-
":tabe|cd %@<CR>", path];
1477-
[vc addVimInput:input];
1463+
NSDictionary *args = [NSDictionary dictionaryWithObjectsAndKeys:
1464+
path, @"path",
1465+
nil];
1466+
[vc sendMessage:NewFileHereMsgID data:[args dictionaryAsData]];
14781467
} else {
14791468
[self launchVimProcessWithArguments:nil workingDirectory:path];
14801469
}

0 commit comments

Comments
 (0)