Skip to content

Commit 78fd2f4

Browse files
committed
Restore the original word-wise movement behavior
1 parent a5663f1 commit 78fd2f4

File tree

3 files changed

+34
-29
lines changed

3 files changed

+34
-29
lines changed

src/host/cmdline.cpp

+19-19
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,16 @@
22
// Licensed under the MIT license.
33

44
#include "precomp.h"
5-
65
#include "cmdline.h"
76

8-
#include "_output.h"
9-
#include "output.h"
10-
#include "stream.h"
11-
#include "_stream.h"
12-
#include "dbcs.h"
13-
#include "handle.h"
14-
#include "misc.h"
15-
#include "../types/inc/convert.hpp"
16-
#include "srvinit.h"
17-
18-
#include "ApiRoutines.h"
19-
207
#include "../interactivity/inc/ServiceLocator.hpp"
218

229
#pragma hdrstop
2310
using Microsoft::Console::Interactivity::ServiceLocator;
2411

2512
// Routine Description:
2613
// - Detects Word delimiters
27-
bool IsWordDelim(const wchar_t wch)
14+
bool IsWordDelim(const wchar_t wch) noexcept
2815
{
2916
// the space character is always a word delimiter. Do not add it to the WordDelimiters global because
3017
// that contains the user configurable word delimiters only.
@@ -33,14 +20,27 @@ bool IsWordDelim(const wchar_t wch)
3320
return true;
3421
}
3522
const auto& delimiters = ServiceLocator::LocateGlobals().WordDelimiters;
36-
if (delimiters.empty())
37-
{
38-
return false;
39-
}
4023
return std::ranges::find(delimiters, wch) != delimiters.end();
4124
}
4225

43-
bool IsWordDelim(const std::wstring_view charData)
26+
bool IsWordDelim(const std::wstring_view& charData) noexcept
4427
{
4528
return charData.size() == 1 && IsWordDelim(charData.front());
4629
}
30+
31+
// Returns a truthy value for delimiters and 0 otherwise.
32+
// The distinction between whitespace and other delimiters allows us to
33+
// implement Windows' inconsistent, but classic, word-wise navigation.
34+
int DelimiterClass(wchar_t wch) noexcept
35+
{
36+
if (wch == L' ')
37+
{
38+
return 1;
39+
}
40+
const auto& delimiters = ServiceLocator::LocateGlobals().WordDelimiters;
41+
if (std::find(delimiters.begin(), delimiters.end(), wch) != delimiters.end())
42+
{
43+
return 2;
44+
}
45+
return 0;
46+
}

src/host/cmdline.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
#include "screenInfo.hpp"
77

88
// Word delimiters
9-
bool IsWordDelim(const wchar_t wch);
10-
bool IsWordDelim(const std::wstring_view charData);
9+
bool IsWordDelim(wchar_t wch) noexcept;
10+
bool IsWordDelim(const std::wstring_view& charData) noexcept;
11+
int DelimiterClass(wchar_t wch) noexcept;

src/host/readDataCooked.cpp

+12-8
Original file line numberDiff line numberDiff line change
@@ -366,11 +366,13 @@ void COOKED_READ_DATA::_handleVkey(uint16_t vkey, DWORD modifiers)
366366
{
367367
if (ctrlPressed)
368368
{
369-
// This would ideally use GraphemePrev() as well, but IsWordDelim() hasn't been refactored yet.
370-
// Seek to the preceding left-hand word boundary.
371-
// (The boundary between a non-word on the left and word on the right.)
372369
--_bufferCursor;
373-
while (_bufferCursor != 0 && (!IsWordDelim(_buffer[_bufferCursor - 1]) || IsWordDelim(_buffer[_bufferCursor])))
370+
while (_bufferCursor != 0 && _buffer[_bufferCursor] == L' ')
371+
{
372+
--_bufferCursor;
373+
}
374+
const auto dc = DelimiterClass(_buffer[_bufferCursor]);
375+
while (_bufferCursor != 0 && DelimiterClass(_buffer[_bufferCursor - 1]) == dc)
374376
{
375377
--_bufferCursor;
376378
}
@@ -388,11 +390,13 @@ void COOKED_READ_DATA::_handleVkey(uint16_t vkey, DWORD modifiers)
388390
{
389391
if (ctrlPressed && vkey == VK_RIGHT)
390392
{
391-
// This would ideally use GraphemeNext() as well, but IsWordDelim() hasn't been refactored yet.
392-
// Seek to the preceding left-hand word boundary.
393-
// (The boundary between a non-word on the left and word on the right.)
394393
++_bufferCursor;
395-
while (_bufferCursor != _buffer.size() && (!IsWordDelim(_buffer[_bufferCursor - 1]) || IsWordDelim(_buffer[_bufferCursor])))
394+
const auto dc = DelimiterClass(_buffer[_bufferCursor - 1]);
395+
while (_bufferCursor != _buffer.size() && dc == DelimiterClass(_buffer[_bufferCursor]))
396+
{
397+
++_bufferCursor;
398+
}
399+
while (_bufferCursor != _buffer.size() && _buffer[_bufferCursor] == L' ')
396400
{
397401
++_bufferCursor;
398402
}

0 commit comments

Comments
 (0)