Skip to content
Snippets Groups Projects
Commit cf291bd7 authored by George Nachman's avatar George Nachman
Browse files

Add Copy Mode.

Also fix the menu opener to not select the last item.
parent 61f56d5a
No related branches found
No related tags found
No related merge requests found
Showing
with 900 additions and 76 deletions
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16E195" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
</dependencies>
<objects>
Loading
Loading
@@ -334,6 +333,11 @@ DQ
<action selector="copyWithStyles:" target="-1" id="B2X-kC-nrq"/>
</connections>
</menuItem>
<menuItem title="Copy Mode" keyEquivalent="C" id="CQc-0U-rfn">
<connections>
<action selector="toggleCopyMode:" target="-1" id="nrd-WW-ADX"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="213">
<connections>
<action selector="paste:" target="-1" id="215"/>
Loading
Loading
@@ -1088,6 +1092,12 @@ DQ
<action selector="showHelp:" target="201" id="hFO-6H-VeJ"/>
</connections>
</menuItem>
<menuItem title="Copy Mode Shortcuts" id="wTB-km-9Qm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="copyModeShortcuts:" target="-1" id="fOs-EL-nnE"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
Loading
Loading
Loading
Loading
@@ -1232,6 +1232,16 @@
A605D4B319CF796800D40343 /* NMSSH.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = A624232519CF70DF00182C08 /* NMSSH.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
A605D4B419CF796F00D40343 /* NMSSH.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = A624232519CF70DF00182C08 /* NMSSH.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
A6099B0518D6B0FD00081FA9 /* iTermWarning.h in Headers */ = {isa = PBXBuildFile; fileRef = A6099B0318D6B0FD00081FA9 /* iTermWarning.h */; };
A60BB37E1EB5149100D76C09 /* iTermCopyModeState.h in Headers */ = {isa = PBXBuildFile; fileRef = A60BB37C1EB5149100D76C09 /* iTermCopyModeState.h */; };
A60BB37F1EB5149100D76C09 /* iTermCopyModeState.m in Sources */ = {isa = PBXBuildFile; fileRef = A60BB37D1EB5149100D76C09 /* iTermCopyModeState.m */; };
A60BB3811EB51D0E00D76C09 /* iTermCopyModeState.m in Sources */ = {isa = PBXBuildFile; fileRef = A60BB37D1EB5149100D76C09 /* iTermCopyModeState.m */; };
A60BB3851EB54B6700D76C09 /* CopyMode@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A60BB3831EB54B6700D76C09 /* CopyMode@2x.png */; };
A60BB3861EB54BD100D76C09 /* CopyMode.png in Resources */ = {isa = PBXBuildFile; fileRef = A60BB3821EB54B6700D76C09 /* CopyMode.png */; };
A60BB3871EB54BD200D76C09 /* CopyMode.png in Resources */ = {isa = PBXBuildFile; fileRef = A60BB3821EB54B6700D76C09 /* CopyMode.png */; };
A60BB3881EB54BD300D76C09 /* CopyMode.png in Resources */ = {isa = PBXBuildFile; fileRef = A60BB3821EB54B6700D76C09 /* CopyMode.png */; };
A60BB3891EB54BD700D76C09 /* CopyMode@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A60BB3831EB54B6700D76C09 /* CopyMode@2x.png */; };
A60BB38A1EB54BD800D76C09 /* CopyMode@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A60BB3831EB54B6700D76C09 /* CopyMode@2x.png */; };
A60BB38B1EB54BD900D76C09 /* CopyMode@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A60BB3831EB54B6700D76C09 /* CopyMode@2x.png */; };
A60BD9131B3913F6007D7F11 /* iTermTextViewAccessibilityHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = A60BD9111B3913F6007D7F11 /* iTermTextViewAccessibilityHelper.h */; };
A60BD9141B3913F6007D7F11 /* iTermTextViewAccessibilityHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = A60BD9111B3913F6007D7F11 /* iTermTextViewAccessibilityHelper.h */; };
A60BD9191B3F5D76007D7F11 /* OpenDirectory.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A60BD9181B3F5D76007D7F11 /* OpenDirectory.framework */; };
Loading
Loading
@@ -3196,6 +3206,10 @@
A6057C161883D12E004A60AF /* broken_image.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = broken_image.png; path = images/broken_image.png; sourceTree = "<group>"; };
A6099B0318D6B0FD00081FA9 /* iTermWarning.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = iTermWarning.h; sourceTree = "<group>"; tabWidth = 4; };
A6099B0418D6B0FD00081FA9 /* iTermWarning.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = iTermWarning.m; sourceTree = "<group>"; tabWidth = 4; };
A60BB37C1EB5149100D76C09 /* iTermCopyModeState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTermCopyModeState.h; sourceTree = "<group>"; };
A60BB37D1EB5149100D76C09 /* iTermCopyModeState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iTermCopyModeState.m; sourceTree = "<group>"; };
A60BB3821EB54B6700D76C09 /* CopyMode.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = CopyMode.png; path = images/CopyMode.png; sourceTree = "<group>"; };
A60BB3831EB54B6700D76C09 /* CopyMode@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "CopyMode@2x.png"; path = "images/CopyMode@2x.png"; sourceTree = "<group>"; };
A60BD9111B3913F6007D7F11 /* iTermTextViewAccessibilityHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTermTextViewAccessibilityHelper.h; sourceTree = "<group>"; };
A60BD9121B3913F6007D7F11 /* iTermTextViewAccessibilityHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = iTermTextViewAccessibilityHelper.m; sourceTree = "<group>"; };
A60BD9181B3F5D76007D7F11 /* OpenDirectory.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenDirectory.framework; path = System/Library/Frameworks/OpenDirectory.framework; sourceTree = SDKROOT; };
Loading
Loading
@@ -4623,6 +4637,8 @@
1D093C131217412B0029F9AD /* Images */ = {
isa = PBXGroup;
children = (
A60BB3821EB54B6700D76C09 /* CopyMode.png */,
A60BB3831EB54B6700D76C09 /* CopyMode@2x.png */,
A68BADF91E0DD52F00E4BB7B /* Touch Bar Function Keys.png */,
A68BADFA1E0DD52F00E4BB7B /* Touch Bar Function Keys@2x.png */,
A68E333D1DE79284003F1D8E /* Color Preset Touch Bar Icon.png */,
Loading
Loading
@@ -5677,6 +5693,8 @@
A62A1F701E6E724B00363EE9 /* iTermMenuOpener.m */,
A668E8A01E7EFEA5005F8758 /* iTermURLStore.h */,
A668E8A11E7EFEA5005F8758 /* iTermURLStore.m */,
A60BB37C1EB5149100D76C09 /* iTermCopyModeState.h */,
A60BB37D1EB5149100D76C09 /* iTermCopyModeState.m */,
);
name = Helpers;
sourceTree = "<group>";
Loading
Loading
@@ -6786,6 +6804,7 @@
A667191D1DCE36C3000CE608 /* iTermHotKeyMigrationHelper.h in Headers */,
A667191E1DCE36C3000CE608 /* iTermCPS.h in Headers */,
A667191F1DCE36C3000CE608 /* PSMDarkHighContrastTabStyle.h in Headers */,
A60BB37E1EB5149100D76C09 /* iTermCopyModeState.h in Headers */,
A66719201DCE36C3000CE608 /* iTermImageMark.h in Headers */,
A66719211DCE36C3000CE608 /* iTermHTTPConnection.h in Headers */,
A66719221DCE36C3000CE608 /* iTermWindowOcclusionChangeMonitor.h in Headers */,
Loading
Loading
@@ -7279,6 +7298,7 @@
1D6ED9B919AEA20D005A7799 /* wrap_to_top.png in Resources */,
A67D0D701A2EE12A003A8B35 /* MainMenu.strings in Resources */,
A67D0D791A2EE12A003A8B35 /* PasteboardHistory.xib in Resources */,
A60BB38B1EB54BD900D76C09 /* CopyMode@2x.png in Resources */,
1D6ED9BB19AEA20D005A7799 /* SmartSelectionRules.plist in Resources */,
A65B72571B1A5D7500F947A7 /* WarningSign@2x.png in Resources */,
1D6ED9BC19AEA20D005A7799 /* closebutton.png in Resources */,
Loading
Loading
@@ -7304,6 +7324,7 @@
A67D0D341A2EE12A003A8B35 /* AboutWindow.xib in Resources */,
1D6ED9C519AEA20D005A7799 /* LogoShadow.png in Resources */,
1D8BBA871B31DC160005A852 /* ChevronDown@2x.png in Resources */,
A60BB3881EB54BD300D76C09 /* CopyMode.png in Resources */,
1D6ED9C919AEA20D005A7799 /* IBarCursor@2x.png in Resources */,
1D6ED9CA19AEA20D005A7799 /* IBarCursorXMR@2x.png in Resources */,
1D6ED9CE19AEA20D005A7799 /* TabClose_Front_Rollover@2x.png in Resources */,
Loading
Loading
@@ -7395,6 +7416,7 @@
1D44D0021CC7F5A600BE5630 /* PTYTextViewTest-golden-testCharacterSelection.png in Resources */,
1D44CFC71CC7F5A600BE5630 /* PTYTextViewTest-golden-nonretina-testRegionStartingWithDWCRight.png in Resources */,
1D44CFA51CC7F5A600BE5630 /* PTYTextViewTest-golden-nonretina-testCursorFilledInBecauseKeyWindowAndActiveTextview.png in Resources */,
A60BB38A1EB54BD800D76C09 /* CopyMode@2x.png in Resources */,
1D44CFCD1CC7F5A600BE5630 /* PTYTextViewTest-golden-nonretina-testSmartCursorColor_allBlack.png in Resources */,
1D44D0741CC7F5A600BE5630 /* PTYTextViewTest-golden-travis-testEmoji.png in Resources */,
1D44D0871CC7F5A600BE5630 /* PTYTextViewTest-golden-travis-testNote.png in Resources */,
Loading
Loading
@@ -7448,6 +7470,7 @@
A673BFE21E176AA300FA2386 /* PTYTextViewTest-golden-travis-testCustomUnderline.png in Resources */,
1D44CFF31CC7F5A600BE5630 /* PTYTextViewTest-golden-testBadge.png in Resources */,
1D44D05E1CC7F5A600BE5630 /* PTYTextViewTest-golden-travis-testBlockCursorReverseVideo.png in Resources */,
A60BB3871EB54BD200D76C09 /* CopyMode.png in Resources */,
1D44D0631CC7F5A600BE5630 /* PTYTextViewTest-golden-travis-testCharacterSelection.png in Resources */,
1D44D0261CC7F5A600BE5630 /* PTYTextViewTest-golden-testNote.png in Resources */,
1D44D0001CC7F5A600BE5630 /* PTYTextViewTest-golden-testBrightBoldOff.png in Resources */,
Loading
Loading
@@ -7854,6 +7877,7 @@
A697101318DFA7D5007E901D /* closebutton.png in Resources */,
534690291C94FF0000B7E4E9 /* overflowImagePressed.png in Resources */,
A6EFF2371D20F6BE00806EEF /* EraseDarkBackground.png in Resources */,
A60BB3891EB54BD700D76C09 /* CopyMode@2x.png in Resources */,
1D8F396B13EB7A2C0025B80B /* BroadcastInput.png in Resources */,
1D44CCDC1CC6A1DE00BE5630 /* Loupe@2x.png in Resources */,
A67D0D501A2EE12A003A8B35 /* FindView.xib in Resources */,
Loading
Loading
@@ -7902,6 +7926,7 @@
A67D0D381A2EE12A003A8B35 /* AdvancedWorkingDirectoryWindow.xib in Resources */,
9D737D5F17495B4100B3334D /* PrefsGeneral.png in Resources */,
1D99C8E71BD59C37001EE1FC /* SearchCursor@2x.png in Resources */,
A60BB3861EB54BD100D76C09 /* CopyMode.png in Resources */,
A6B70FC119830F0D007A4284 /* NewOutput.png in Resources */,
1DA76A0B1B30892900CB272A /* iTermTipWindowController.xib in Resources */,
A67D0D6B1A2EE12A003A8B35 /* iTermPasteSpecialWindow.xib in Resources */,
Loading
Loading
@@ -8144,6 +8169,7 @@
A6BDB0AF1B45FC9E00F511E6 /* PTYTextViewTest-golden-testUseNonAsciiFont.png in Resources */,
1D44CD991CC7E8D600BE5630 /* PTYTextViewTest-golden-nonretina-testBasicDraw.png in Resources */,
1D44CDA11CC7E8D600BE5630 /* PTYTextViewTest-golden-nonretina-testBoxDrawing.png in Resources */,
A60BB3851EB54B6700D76C09 /* CopyMode@2x.png in Resources */,
1D44D0BD1CC7F5A700BE5630 /* PTYTextViewTest-golden-travis-testBlockCursorReverseVideo.png in Resources */,
1D44CEB61CC7F00800BE5630 /* PTYTextViewTest-golden-travis-testDimmingTextAndMinimumContrast.png in Resources */,
1D44CDD71CC7E8D600BE5630 /* PTYTextViewTest-golden-nonretina-testSmartCursorColor_frameManyGrayOneWhiteOneBlack.png in Resources */,
Loading
Loading
@@ -8591,6 +8617,7 @@
A6C762DB1B45C52B00E3C992 /* PTYSession.m in Sources */,
A6C763291B45C52B00E3C992 /* PTYFontInfo.m in Sources */,
A6C763EB1B45C71900E3C992 /* UKSystemInfo.m in Sources */,
A60BB3811EB51D0E00D76C09 /* iTermCopyModeState.m in Sources */,
A6C763B31B45C52B00E3C992 /* PasswordTrigger.m in Sources */,
A6C763531B45C52B00E3C992 /* iTermOpenQuicklyModel.m in Sources */,
A6C7633D1B45C52B00E3C992 /* FindView.m in Sources */,
Loading
Loading
@@ -8800,6 +8827,7 @@
A61F8E301E62591800D315D0 /* iTermFakeUserDefaults.m in Sources */,
A602516B1CCD40D9009BABF1 /* iTermNSURLCategoryTest.m in Sources */,
A6ACD1F81B62F2210095CB57 /* iTermRuleTest.m in Sources */,
A60BB37F1EB5149100D76C09 /* iTermCopyModeState.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
images/CopyMode.png

1.51 KiB

File added
images/CopyMode@2x.png

1.39 KiB

Loading
Loading
@@ -436,6 +436,7 @@ typedef enum {
 
@property(nonatomic, readonly) NSDictionary<NSString *, NSString *> *keyLabels;
@property(nonatomic, readonly) iTermRestorableSession *restorableSession;
@property(nonatomic) BOOL copyMode;
 
#pragma mark - methods
 
Loading
Loading
Loading
Loading
@@ -17,6 +17,7 @@
#import "iTermColorPresets.h"
#import "iTermCommandHistoryCommandUseMO+Addtions.h"
#import "iTermController.h"
#import "iTermCopyModeState.h"
#import "iTermGrowlDelegate.h"
#import "iTermHotKeyController.h"
#import "iTermInitialDirectory.h"
Loading
Loading
@@ -466,6 +467,8 @@ static const NSUInteger kMaxHosts = 100;
double _slowFrameRate;
 
uint32_t _autoLogId;
iTermCopyModeState *_copyModeState;
}
 
+ (void)registerSessionInArrangement:(NSDictionary *)arrangement {
Loading
Loading
@@ -669,7 +672,8 @@ ITERM_WEAKLY_REFERENCEABLE
[_updateSubscriptions release];
[_promptSubscriptions release];
[_locationChangeSubscriptions release];
[_copyModeState release];
[[NSNotificationCenter defaultCenter] removeObserver:self];
 
if (_dvrDecoder) {
Loading
Loading
@@ -756,6 +760,40 @@ ITERM_WEAKLY_REFERENCEABLE
}
}
 
- (void)educateAboutCopyMode {
[iTermMenuOpener revealMenuWithPath:@[ @"Help", @"Copy Mode Shortcuts" ]
message:@"You have entered Copy Mode.\nWhile in copy mode, you use keyboard\nshortcuts to modify the selection.\nYou can always find the list of\nshortcuts in the Help menu."];
}
- (void)setCopyMode:(BOOL)copyMode {
if (copyMode) {
NSString *const key = @"NoSyncHaveUsedCopyMode";
if ([[NSUserDefaults standardUserDefaults] objectForKey:key] == nil) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self educateAboutCopyMode];
});
}
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:key];
}
_copyMode = copyMode;
[_copyModeState autorelease];
if (copyMode) {
_copyModeState = [[iTermCopyModeState alloc] init];
_copyModeState.coord = VT100GridCoordMake(_screen.cursorX - 1,
_screen.cursorY - 1 + _screen.numberOfScrollbackLines);
_copyModeState.numberOfLines = _screen.numberOfLines;
_copyModeState.textView = _textview;
} else {
if (_textview.selection.live) {
[_textview.selection endLiveSelection];
}
_copyModeState = nil;
}
[_textview setNeedsDisplay:YES]; // TODO optimize
}
- (void)updateVariables {
if (_name) {
_variables[kVariableKeySessionName] = [[_name copy] autorelease];
Loading
Loading
@@ -1935,6 +1973,157 @@ ITERM_WEAKLY_REFERENCEABLE
[self writeTaskImpl:string encoding:encoding forceEncoding:forceEncoding canBroadcast:NO];
}
 
- (void)handleKeyPressInCopyMode:(NSEvent *)event {
NSString *string = event.charactersIgnoringModifiers;
unichar code = [string length] > 0 ? [string characterAtIndex:0] : 0;
NSUInteger mask = (NSAlternateKeyMask | NSControlKeyMask | NSCommandKeyMask);
BOOL moved = NO;
if ((event.modifierFlags & mask) == NSControlKeyMask) {
switch (code) {
case 2: // ^B
moved = [_copyModeState pageUp];
break;
case 6: // ^F
moved = [_copyModeState pageDown];
break;
case ' ':
_copyModeState.selecting = !_copyModeState.selecting;
_copyModeState.mode = kiTermSelectionModeCharacter;
break;
case 'c':
self.copyMode = NO;
break;
case 'g':
self.copyMode = NO;
break;
case 'k':
[_textview copySelectionAccordingToUserPreferences];
self.copyMode = NO;
break;
case 'v':
_copyModeState.selecting = !_copyModeState.selecting;
_copyModeState.mode = kiTermSelectionModeBox;
break;
}
} else if ((event.modifierFlags & mask) == NSAlternateKeyMask) {
switch (code) {
case 'b':
case NSLeftArrowFunctionKey:
moved = [_copyModeState moveBackwardWord];
break;
case 'f':
case NSRightArrowFunctionKey:
moved = [_copyModeState moveForwardWord];
break;
case 'm':
moved = [_copyModeState moveToStartOfIndentation];
break;
}
} else if ((event.modifierFlags & mask) == 0) {
switch (code) {
case NSPageUpFunctionKey:
moved = [_copyModeState pageUp];
break;
case NSPageDownFunctionKey:
moved = [_copyModeState pageDown];
break;
case '\t':
if (event.modifierFlags & NSShiftKeyMask) {
moved = [_copyModeState moveBackwardWord];
} else {
moved = [_copyModeState moveForwardWord];
}
break;
case '\n':
case '\r':
moved = [_copyModeState moveToStartOfNextLine];
break;
case 27:
case 'q':
self.copyMode = NO;
_copyModeState.selecting = NO;
moved = YES;
break;
case ' ':
case 'v':
_copyModeState.selecting = !_copyModeState.selecting;
_copyModeState.mode = kiTermSelectionModeCharacter;
break;
case 'b':
moved = [_copyModeState moveBackwardWord];
break;
case '0':
moved = [_copyModeState moveToStartOfLine];
break;
case 'H':
moved = [_copyModeState moveToTopOfVisibleArea];
break;
case 'G':
moved = [_copyModeState moveToEnd];
break;
case 'L':
moved = [_copyModeState moveToBottomOfVisibleArea];
break;
case 'M':
moved = [_copyModeState moveToMiddleOfVisibleArea];
break;
case 'V':
_copyModeState.selecting = !_copyModeState.selecting;
_copyModeState.mode = kiTermSelectionModeLine;
break;
case 'g':
moved = [_copyModeState moveToStart];
break;
case 'h':
case NSLeftArrowFunctionKey:
moved = [_copyModeState moveLeft];
break;
case 'j':
case NSDownArrowFunctionKey:
moved = [_copyModeState moveDown];
break;
case 'k':
case NSUpArrowFunctionKey:
moved = [_copyModeState moveUp];
break;
case 'l':
case NSRightArrowFunctionKey:
moved = [_copyModeState moveRight];
break;
case 'o':
[_copyModeState swap];
moved = YES;
break;
case 'w':
moved = [_copyModeState moveForwardWord];
break;
case 'y':
[_textview copySelectionAccordingToUserPreferences];
self.copyMode = NO;
break;
case '[':
moved = [_copyModeState previousMark];
break;
case ']':
moved = [_copyModeState nextMark];
break;
case '^':
moved = [_copyModeState moveToStartOfIndentation];
break;
case '$':
moved = [_copyModeState moveToEndOfLine];
break;
}
}
if (moved) {
if (self.copyMode) {
[_textview scrollLineNumberRangeIntoView:VT100GridRangeMake(_copyModeState.coord.y, 1)];
}
[self.textview setNeedsDisplay:YES]; // TODO optimize this and draw less
}
}
- (void)handleKeypressInTmuxGateway:(unichar)unicode
{
if (unicode == 27) {
Loading
Loading
@@ -2146,8 +2335,9 @@ ITERM_WEAKLY_REFERENCEABLE
DLog(@"Session %@ begins executing tokens", self);
int n = CVectorCount(vector);
 
if (_shell.paused) {
// Session was closed. The close may be undone, so queue up tokens.
if (_shell.paused || _copyMode) {
// Session was closed or is not accepting new tokens because it's in copy mode. These can
// be handled later (unclose or exit copy mode), so queu them up.
for (int i = 0; i < n; i++) {
[_queuedTokens addObject:CVectorGetObject(vector, i)];
}
Loading
Loading
@@ -5196,6 +5386,10 @@ ITERM_WEAKLY_REFERENCEABLE
}
 
- (BOOL)textViewShouldAcceptKeyDownEvent:(NSEvent *)event {
if (_copyMode) {
[self handleKeyPressInCopyMode:event];
return NO;
}
if (event.keyCode == kVK_Return && _fakePromptDetectedAbsLine >= 0) {
[self didInferEndOfCommand];
}
Loading
Loading
@@ -6577,6 +6771,14 @@ ITERM_WEAKLY_REFERENCEABLE
[_view setHoverURL:url];
}
 
- (BOOL)textViewCopyMode {
return _copyMode;
}
- (VT100GridCoord)textViewCopyModeCursorCoord {
return _copyModeState.coord;
}
- (void)bury {
[_textview setDataSource:nil];
[_textview setDelegate:nil];
Loading
Loading
Loading
Loading
@@ -51,7 +51,16 @@ typedef NS_ENUM(NSInteger, PTYTextViewSelectionEndpoint) {
 
typedef NS_ENUM(NSInteger, PTYTextViewSelectionExtensionDirection) {
kPTYTextViewSelectionExtensionDirectionLeft,
kPTYTextViewSelectionExtensionDirectionRight
kPTYTextViewSelectionExtensionDirectionRight,
// These ignore the unit and are simple movements.
kPTYTextViewSelectionExtensionDirectionUp,
kPTYTextViewSelectionExtensionDirectionDown,
kPTYTextViewSelectionExtensionDirectionStartOfLine,
kPTYTextViewSelectionExtensionDirectionEndOfLine,
kPTYTextViewSelectionExtensionDirectionTop,
kPTYTextViewSelectionExtensionDirectionBottom,
kPTYTextViewSelectionExtensionDirectionStartOfIndentation,
};
 
typedef NS_ENUM(NSInteger, PTYTextViewSelectionExtensionUnit) {
Loading
Loading
@@ -178,6 +187,9 @@ typedef NS_ENUM(NSInteger, PTYTextViewSelectionExtensionUnit) {
- (void)textViewBurySession;
- (void)textViewShowHoverURL:(NSString *)url;
 
- (BOOL)textViewCopyMode;
- (VT100GridCoord)textViewCopyModeCursorCoord;
@end
 
@interface PTYTextView : NSView <
Loading
Loading
@@ -308,6 +320,9 @@ typedef void (^PTYTextViewDrawingHookBlock)(iTermTextDrawingHelper *);
// Returns the desired height of this view that exactly fits its contents.
@property(nonatomic, readonly) CGFloat desiredHeight;
 
// Lines that are currently visible on the screen.
@property(nonatomic, readonly) VT100GridRange rangeOfVisibleLines;
// Returns the size of a cell for a given font. hspace and vspace are multipliers and the width
// and height.
+ (NSSize)charSizeForFont:(NSFont*)aFont
Loading
Loading
@@ -507,6 +522,17 @@ typedef void (^PTYTextViewDrawingHookBlock)(iTermTextDrawingHelper *);
inDirection:(PTYTextViewSelectionExtensionDirection)direction
by:(PTYTextViewSelectionExtensionUnit)unit;
 
- (void)moveSelectionEndpoint:(PTYTextViewSelectionEndpoint)endpoint
inDirection:(PTYTextViewSelectionExtensionDirection)direction
by:(PTYTextViewSelectionExtensionUnit)unit
cursorCoord:(VT100GridCoord)cursorCoord;
- (VT100GridWindowedRange)rangeByExtendingRange:(VT100GridWindowedRange)existingRange
endpoint:(PTYTextViewSelectionEndpoint)endpoint
direction:(PTYTextViewSelectionExtensionDirection)direction
extractor:(iTermTextExtractor *)extractor
unit:(PTYTextViewSelectionExtensionUnit)unit;
// For focus follows mouse. Allows a new split pane to become focused even though the mouse pointer
// is elsewhere. Records the mouse position. Refuses first responder as long as the mouse doesn't
// move.
Loading
Loading
Loading
Loading
@@ -1124,7 +1124,9 @@ static const int kDragThreshold = 3;
_drawingHelper.unicodeVersion = [_delegate textViewUnicodeVersion];
_drawingHelper.asciiLigatures = _primaryFont.hasDefaultLigatures || _asciiLigatures;
_drawingHelper.nonAsciiLigatures = _secondaryFont.hasDefaultLigatures || _nonAsciiLigatures;
_drawingHelper.copyMode = _delegate.textViewCopyMode;
_drawingHelper.copyModeCursorCoord = _delegate.textViewCopyModeCursorCoord;
const NSRect *rectArray;
NSInteger rectCount;
[self getRectsBeingDrawn:&rectArray count:&rectCount];
Loading
Loading
@@ -1178,6 +1180,8 @@ static const int kDragThreshold = 3;
visible:[_delegate textViewSuppressingAllOutput]];
[_indicatorsHelper setIndicator:kiTermIndicatorZoomedIn
visible:[_delegate textViewIsZoomedIn]];
[_indicatorsHelper setIndicator:kiTermIndicatorCopyMode
visible:[_delegate textViewCopyMode]];
NSRect rect = self.visibleRect;
rect.size.width -= rightMargin;
[_indicatorsHelper drawInFrame:rect];
Loading
Loading
@@ -1951,11 +1955,19 @@ static const int kDragThreshold = 3;
return VT100GridCoordMake(p.x, p.y);
}
 
// TODO: this should return a VT100GridCoord but it confusingly returns an NSPoint.
//
// If allowRightMarginOverflow is YES then the returned value's x coordinate may be equal to
// dataSource.width. If NO, then it will always be less than dataSource.width.
- (NSPoint)windowLocationToRowCol:(NSPoint)locationInWindow
allowRightMarginOverflow:(BOOL)allowRightMarginOverflow {
NSPoint locationInTextView = [self convertPoint:locationInWindow fromView: nil];
VT100GridCoord coord = [self coordForPoint:locationInTextView allowRightMarginOverflow:allowRightMarginOverflow];
return NSMakePoint(coord.x, coord.y);
}
- (VT100GridCoord)coordForPoint:(NSPoint)locationInTextView allowRightMarginOverflow:(BOOL)allowRightMarginOverflow {
int x, y;
int width = [_dataSource width];
 
Loading
Loading
@@ -1974,7 +1986,7 @@ static const int kDragThreshold = 3;
x = MIN(x, limit);
y = MIN(y, [_dataSource numberOfLines] - 1);
 
return NSMakePoint(x, y);
return VT100GridCoordMake(x, y);
}
 
- (NSPoint)clickPoint:(NSEvent *)event allowRightMarginOverflow:(BOOL)allowRightMarginOverflow {
Loading
Loading
@@ -3876,6 +3888,108 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) {
return [self menuAtCoord:VT100GridCoordMake(-1, -1)];
}
 
- (VT100GridWindowedRange)rangeByMovingStartOfRange:(VT100GridWindowedRange)existingRange
toTopWithExtractor:(iTermTextExtractor *)extractor {
VT100GridWindowedRange newRange = existingRange;
newRange.coordRange.start = VT100GridCoordMake(0, 0);
return newRange;
}
- (VT100GridWindowedRange)rangeByMovingStartOfRange:(VT100GridWindowedRange)existingRange
toBottomWithExtractor:(iTermTextExtractor *)extractor {
VT100GridWindowedRange newRange = existingRange;
int maxY = MAX(0, [_dataSource numberOfLines] - 1);
newRange.coordRange.start = VT100GridCoordMake(MAX(0, _dataSource.width - 1), maxY);
return newRange;
}
- (VT100GridWindowedRange)rangeByMovingStartOfRange:(VT100GridWindowedRange)existingRange
toStartOfLineWithExtractor:(iTermTextExtractor *)extractor {
VT100GridWindowedRange newRange = existingRange;
newRange.coordRange.start.x = existingRange.columnWindow.location;
return newRange;
}
- (VT100GridWindowedRange)rangeByMovingStartOfRange:(VT100GridWindowedRange)existingRange
toEndOfLineWithExtractor:(iTermTextExtractor *)extractor {
VT100GridWindowedRange newRange = existingRange;
newRange.coordRange.start.x = [extractor lengthOfLine:newRange.coordRange.start.y];
return newRange;
}
- (VT100GridWindowedRange)rangeByMovingStartOfRange:(VT100GridWindowedRange)existingRange
toStartOfIndentationWithExtractor:(iTermTextExtractor *)extractor {
VT100GridWindowedRange newRange = existingRange;
newRange.coordRange.start.x = [extractor startOfIndentationOnLine:existingRange.coordRange.start.y];
return newRange;
}
- (VT100GridWindowedRange)rangeByMovingStartOfRange:(VT100GridWindowedRange)existingRange
upWithExtractor:(iTermTextExtractor *)extractor {
VT100GridWindowedRange newRange = existingRange;
newRange.coordRange.start.y = MAX(0, existingRange.coordRange.start.y - 1);
return newRange;
}
- (VT100GridWindowedRange)rangeByMovingStartOfRange:(VT100GridWindowedRange)existingRange
downWithExtractor:(iTermTextExtractor *)extractor {
VT100GridWindowedRange newRange = existingRange;
int maxY = [_dataSource numberOfLines];
newRange.coordRange.start.y = MIN(maxY - 1, existingRange.coordRange.start.y + 1);
return newRange;
}
- (VT100GridWindowedRange)rangeByMovingEndOfRange:(VT100GridWindowedRange)existingRange
toTopWithExtractor:(iTermTextExtractor *)extractor {
VT100GridWindowedRange newRange = existingRange;
newRange.coordRange.end = VT100GridCoordMake(0, 0);
return newRange;
}
- (VT100GridWindowedRange)rangeByMovingEndOfRange:(VT100GridWindowedRange)existingRange
toBottomWithExtractor:(iTermTextExtractor *)extractor {
VT100GridWindowedRange newRange = existingRange;
int maxY = MAX(0, [_dataSource numberOfLines] - 1);
newRange.coordRange.end = VT100GridCoordMake(MAX(0, _dataSource.width - 1), maxY);
return newRange;
}
- (VT100GridWindowedRange)rangeByMovingEndOfRange:(VT100GridWindowedRange)existingRange
toStartOfLineWithExtractor:(iTermTextExtractor *)extractor {
VT100GridWindowedRange newRange = existingRange;
newRange.coordRange.end.x = existingRange.columnWindow.location;
return newRange;
}
- (VT100GridWindowedRange)rangeByMovingEndOfRange:(VT100GridWindowedRange)existingRange
toEndOfLineWithExtractor:(iTermTextExtractor *)extractor {
VT100GridWindowedRange newRange = existingRange;
newRange.coordRange.end.x = [extractor lengthOfLine:newRange.coordRange.end.y];
return newRange;
}
- (VT100GridWindowedRange)rangeByMovingEndOfRange:(VT100GridWindowedRange)existingRange
toStartOfIndentationWithExtractor:(iTermTextExtractor *)extractor {
VT100GridWindowedRange newRange = existingRange;
newRange.coordRange.end.x = [extractor startOfIndentationOnLine:existingRange.coordRange.end.y];
return newRange;
}
- (VT100GridWindowedRange)rangeByMovingEndOfRange:(VT100GridWindowedRange)existingRange
upWithExtractor:(iTermTextExtractor *)extractor {
VT100GridWindowedRange newRange = existingRange;
newRange.coordRange.end.y = MAX(0, existingRange.coordRange.end.y - 1);
return newRange;
}
- (VT100GridWindowedRange)rangeByMovingEndOfRange:(VT100GridWindowedRange)existingRange
downWithExtractor:(iTermTextExtractor *)extractor {
VT100GridWindowedRange newRange = existingRange;
int maxY = [_dataSource numberOfLines];
newRange.coordRange.end.y = MIN(maxY - 1, existingRange.coordRange.end.y + 1);
return newRange;
}
- (VT100GridWindowedRange)rangeByMovingStartOfRangeBack:(VT100GridWindowedRange)existingRange
extractor:(iTermTextExtractor *)extractor
unit:(PTYTextViewSelectionExtensionUnit)unit {
Loading
Loading
@@ -4099,30 +4213,76 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) {
switch (endpoint) {
case kPTYTextViewSelectionEndpointStart:
switch (direction) {
case kPTYTextViewSelectionExtensionDirectionUp:
return [self rangeByMovingStartOfRange:existingRange
upWithExtractor:extractor];
case kPTYTextViewSelectionExtensionDirectionLeft:
return [self rangeByMovingStartOfRangeBack:existingRange
extractor:extractor
unit:unit];
 
case kPTYTextViewSelectionExtensionDirectionDown:
return [self rangeByMovingStartOfRange:existingRange
downWithExtractor:extractor];
case kPTYTextViewSelectionExtensionDirectionRight:
return [self rangeByMovingStartOfRangeForward:existingRange
extractor:extractor
unit:unit];
case kPTYTextViewSelectionExtensionDirectionStartOfLine:
return [self rangeByMovingStartOfRange:existingRange toStartOfLineWithExtractor:extractor];
case kPTYTextViewSelectionExtensionDirectionEndOfLine:
return [self rangeByMovingStartOfRange:existingRange toEndOfLineWithExtractor:extractor];
case kPTYTextViewSelectionExtensionDirectionTop:
return [self rangeByMovingStartOfRange:existingRange toTopWithExtractor:extractor];
case kPTYTextViewSelectionExtensionDirectionBottom:
return [self rangeByMovingStartOfRange:existingRange toBottomWithExtractor:extractor];
case kPTYTextViewSelectionExtensionDirectionStartOfIndentation:
return [self rangeByMovingStartOfRange:existingRange toStartOfIndentationWithExtractor:extractor];
}
assert(false);
break;
case kPTYTextViewSelectionEndpointEnd:
switch (direction) {
case kPTYTextViewSelectionExtensionDirectionUp:
return [self rangeByMovingEndOfRange:existingRange
upWithExtractor:extractor];
case kPTYTextViewSelectionExtensionDirectionLeft:
return [self rangeByMovingEndOfRangeBack:existingRange
extractor:extractor
unit:unit];
 
case kPTYTextViewSelectionExtensionDirectionDown:
return [self rangeByMovingEndOfRange:existingRange
downWithExtractor:extractor];
case kPTYTextViewSelectionExtensionDirectionRight:
return [self rangeByMovingEndOfRangeForward:existingRange
extractor:extractor
unit:unit];
case kPTYTextViewSelectionExtensionDirectionStartOfLine:
return [self rangeByMovingEndOfRange:existingRange toStartOfLineWithExtractor:extractor];
case kPTYTextViewSelectionExtensionDirectionEndOfLine:
return [self rangeByMovingEndOfRange:existingRange toEndOfLineWithExtractor:extractor];
case kPTYTextViewSelectionExtensionDirectionTop:
return [self rangeByMovingEndOfRange:existingRange toTopWithExtractor:extractor];
case kPTYTextViewSelectionExtensionDirectionBottom:
return [self rangeByMovingEndOfRange:existingRange toBottomWithExtractor:extractor];
case kPTYTextViewSelectionExtensionDirectionStartOfIndentation:
return [self rangeByMovingEndOfRange:existingRange toStartOfIndentationWithExtractor:extractor];
}
assert(false);
break;
Loading
Loading
@@ -4156,9 +4316,21 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) {
return NO;
}
 
- (VT100GridCoord)cursorCoord {
return VT100GridCoordMake(_dataSource.cursorX - 1,
_dataSource.numberOfScrollbackLines + _dataSource.cursorY - 1);
}
- (void)moveSelectionEndpoint:(PTYTextViewSelectionEndpoint)endpoint
inDirection:(PTYTextViewSelectionExtensionDirection)direction
by:(PTYTextViewSelectionExtensionUnit)unit {
[self moveSelectionEndpoint:endpoint inDirection:direction by:unit cursorCoord:[self cursorCoord]];
}
- (void)moveSelectionEndpoint:(PTYTextViewSelectionEndpoint)endpoint
inDirection:(PTYTextViewSelectionExtensionDirection)direction
by:(PTYTextViewSelectionExtensionUnit)unit
cursorCoord:(VT100GridCoord)cursorCoord {
// Ensure the unit is valid, since it comes from preferences.
if (![self unitIsValid:unit]) {
XLog(@"ERROR: Unrecognized unit enumerated value %@, treating as character.", @(unit));
Loading
Loading
@@ -4174,9 +4346,7 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) {
VT100GridWindowedRange existingRange;
// Create a selection at the cursor if none exists.
if (!sub) {
VT100GridCoord coord =
VT100GridCoordMake(_dataSource.cursorX - 1,
_dataSource.numberOfScrollbackLines + _dataSource.cursorY - 1);
VT100GridCoord coord = cursorCoord;
VT100GridRange columnWindow = extractor.logicalWindow;
existingRange = VT100GridWindowedRangeMake(VT100GridCoordRangeMake(coord.x, coord.y, coord.x, coord.y),
columnWindow.location,
Loading
Loading
@@ -5781,17 +5951,29 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) {
[self scrollRectToVisible:aFrame];
}
 
- (void)scrollBottomOfRectToBottomOfVisibleArea:(NSRect)rect {
NSPoint p = rect.origin;
p.y += rect.size.height;
- (NSRect)visibleContentRect {
NSRect visibleRect = [[self enclosingScrollView] documentVisibleRect];
visibleRect.size.height -= [self excess];
visibleRect.size.height -= [iTermAdvancedSettingsModel terminalVMargin];
return visibleRect;
}
- (void)scrollBottomOfRectToBottomOfVisibleArea:(NSRect)rect {
NSPoint p = rect.origin;
p.y += rect.size.height;
NSRect visibleRect = [self visibleContentRect];
p.y -= visibleRect.size.height;
p.y = MAX(0, p.y);
[[[self enclosingScrollView] contentView] scrollToPoint:p];
}
 
- (VT100GridRange)rangeOfVisibleLines {
NSRect visibleRect = [self visibleContentRect];
int start = [self coordForPoint:visibleRect.origin allowRightMarginOverflow:NO].y;
int end = [self coordForPoint:NSMakePoint(0, NSMaxY(visibleRect) - 1) allowRightMarginOverflow:NO].y;
return VT100GridRangeMake(start, MAX(0, end - start));
}
- (void)scrollLineNumberRangeIntoView:(VT100GridRange)range {
NSRect visibleRect = [[self enclosingScrollView] documentVisibleRect];
int firstVisibleLine = visibleRect.origin.y / _lineHeight;
Loading
Loading
Loading
Loading
@@ -4927,6 +4927,16 @@ ITERM_WEAKLY_REFERENCEABLE
}
}
 
- (IBAction)toggleCopyMode:(id)sender {
PTYSession *session = self.currentSession;
session.copyMode = !session.copyMode;
}
- (IBAction)copyModeShortcuts:(id)sender {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://iterm2.com/documentation-copymode.html"]];
}
- (void)showRangeOfLines:(NSRange)rangeOfLines inSession:(PTYSession *)oldSession {
PTYSession *syntheticSession = [self syntheticSessionForSession:oldSession];
syntheticSession.textview.cursorVisible = NO;
Loading
Loading
Loading
Loading
@@ -218,7 +218,7 @@
}
}
 
if (okToRemap && [currentSession hasActionableKeyMappingForEvent:event]) {
if (okToRemap && [currentSession hasActionableKeyMappingForEvent:event] && !currentSession.copyMode) {
// Remap key.
DLog(@"Remapping to actionable event");
[currentSession keyDown:event];
Loading
Loading
//
// iTermCopyModeState.h
// iTerm2
//
// Created by George Nachman on 4/29/17.
//
//
#import <Foundation/Foundation.h>
#import "iTermSelection.h"
#import "VT100GridTypes.h"
@class PTYTextView;
@interface iTermCopyModeState : NSObject
@property (nonatomic) VT100GridCoord coord;
@property (nonatomic) int numberOfLines;
@property (nonatomic, strong) PTYTextView *textView;
@property (nonatomic) BOOL selecting;
@property (nonatomic, readonly) VT100GridCoord start;
@property (nonatomic) iTermSelectionMode mode;
- (BOOL)moveBackwardWord;
- (BOOL)moveForwardWord;
- (BOOL)moveLeft;
- (BOOL)moveRight;
- (BOOL)moveUp;
- (BOOL)moveDown;
- (BOOL)moveToStartOfNextLine;
- (BOOL)pageUp;
- (BOOL)pageDown;
- (BOOL)previousMark;
- (BOOL)nextMark;
- (BOOL)moveToStart;
- (BOOL)moveToEnd;
- (BOOL)moveToStartOfIndentation;
- (BOOL)moveToBottomOfVisibleArea;
- (BOOL)moveToMiddleOfVisibleArea;
- (BOOL)moveToTopOfVisibleArea;
- (BOOL)moveToStartOfLine;
- (BOOL)moveToEndOfLine;
- (void)swap;
@end
//
// iTermCopyModeState.m
// iTerm2
//
// Created by George Nachman on 4/29/17.
//
//
#import "iTermCopyModeState.h"
#import "iTermSelection.h"
#import "iTermTextExtractor.h"
#import "PTYTextView.h"
#import "PTYTextViewDataSource.h"
@implementation iTermCopyModeState
- (instancetype)init {
self = [super init];
if (self) {
_mode = kiTermSelectionModeCharacter;
}
return self;
}
- (void)dealloc {
[_textView release];
[super dealloc];
}
- (BOOL)moveBackwardWord {
return [self moveInDirection:kPTYTextViewSelectionExtensionDirectionLeft unit:kPTYTextViewSelectionExtensionUnitWord];
}
- (BOOL)moveForwardWord {
return [self moveInDirection:kPTYTextViewSelectionExtensionDirectionRight unit:kPTYTextViewSelectionExtensionUnitWord];
}
- (BOOL)moveLeft {
return [self moveInDirection:kPTYTextViewSelectionExtensionDirectionLeft unit:kPTYTextViewSelectionExtensionUnitCharacter];
}
- (BOOL)moveRight {
return [self moveInDirection:kPTYTextViewSelectionExtensionDirectionRight unit:kPTYTextViewSelectionExtensionUnitCharacter];
}
- (BOOL)moveUp {
return [self moveInDirection:kPTYTextViewSelectionExtensionDirectionUp unit:kPTYTextViewSelectionExtensionUnitCharacter];
}
- (BOOL)moveDown {
return [self moveInDirection:kPTYTextViewSelectionExtensionDirectionDown unit:kPTYTextViewSelectionExtensionUnitCharacter];
}
- (BOOL)moveToStartOfNextLine {
BOOL moved = [self moveDown];
if (moved) {
[self moveToStartOfLine];
}
return moved;
}
- (BOOL)moveToStartOfLine {
return [self moveInDirection:kPTYTextViewSelectionExtensionDirectionStartOfLine unit:kPTYTextViewSelectionExtensionUnitCharacter];
}
- (BOOL)moveToEndOfLine {
return [self moveInDirection:kPTYTextViewSelectionExtensionDirectionEndOfLine unit:kPTYTextViewSelectionExtensionUnitCharacter];
}
- (BOOL)pageUp {
BOOL moved = NO;
for (int i = 0; i < _textView.dataSource.height; i++) {
if ([self moveUp]) {
moved = YES;
}
}
return moved;
}
- (BOOL)pageDown {
BOOL moved = NO;
for (int i = 0; i < _textView.dataSource.height; i++) {
if ([self moveDown]) {
moved = YES;
}
}
return moved;
}
- (BOOL)moveToBottomOfVisibleArea {
BOOL moved = NO;
VT100GridRange range = [_textView rangeOfVisibleLines];
int destination = range.location + range.length;
int n = MAX(0, destination - _coord.y);
for (int i = 0; i < n; i++) {
if ([self moveDown]) {
moved = YES;
}
}
return moved;
}
- (BOOL)moveToMiddleOfVisibleArea {
BOOL moved = NO;
VT100GridRange range = [_textView rangeOfVisibleLines];
int destination = range.location + range.length / 2;
int n = destination - _coord.y;
for (int i = 0; i < abs(n); i++) {
BOOL result;
if (n < 0) {
result = [self moveUp];
} else {
result = [self moveDown];
}
if (result) {
moved = YES;
}
}
return moved;
}
- (BOOL)moveToTopOfVisibleArea {
BOOL moved = NO;
VT100GridRange range = [_textView rangeOfVisibleLines];
int destination = range.location;
int n = MAX(0, _coord.y - destination);
for (int i = 0; i < n; i++) {
if ([self moveUp]) {
moved = YES;
}
}
return moved;
}
- (BOOL)previousMark {
return [self moveInDirection:kPTYTextViewSelectionExtensionDirectionLeft unit:kPTYTextViewSelectionExtensionUnitMark];
}
- (BOOL)nextMark {
return [self moveInDirection:kPTYTextViewSelectionExtensionDirectionRight unit:kPTYTextViewSelectionExtensionUnitMark];
}
- (BOOL)moveToStart {
return [self moveInDirection:kPTYTextViewSelectionExtensionDirectionTop unit:kPTYTextViewSelectionExtensionUnitCharacter];
}
- (BOOL)moveToEnd {
return [self moveInDirection:kPTYTextViewSelectionExtensionDirectionBottom unit:kPTYTextViewSelectionExtensionUnitCharacter];
}
- (BOOL)moveToStartOfIndentation {
return [self moveInDirection:kPTYTextViewSelectionExtensionDirectionStartOfIndentation unit:kPTYTextViewSelectionExtensionUnitCharacter];
}
- (void)setSelecting:(BOOL)selecting {
if (selecting == _selecting) {
return;
}
_selecting = selecting;
if (selecting) {
_start = _coord;
}
}
- (void)swap {
VT100GridCoord temp = _coord;
_coord = _start;
_start = temp;
}
- (void)setMode:(iTermSelectionMode)mode {
_mode = mode;
if (_selecting && mode == kiTermSelectionModeLine) {
[_textView.selection beginSelectionAt:_start
mode:_mode
resume:NO
append:NO];
[_textView.selection moveSelectionEndpointTo:_coord];
[_textView.selection endLiveSelection];
}
}
#pragma mark - Private
- (PTYTextViewSelectionEndpoint)endpointWithDirection:(PTYTextViewSelectionExtensionDirection)direction {
switch (VT100GridCoordOrder(_start, _coord)) {
case NSOrderedSame:
if (direction == kPTYTextViewSelectionExtensionDirectionLeft || direction == kPTYTextViewSelectionExtensionDirectionUp) {
return kPTYTextViewSelectionEndpointStart;
} else {
return kPTYTextViewSelectionEndpointEnd;
}
case NSOrderedAscending:
return kPTYTextViewSelectionEndpointEnd;
case NSOrderedDescending:
return kPTYTextViewSelectionEndpointStart;
}
}
- (VT100GridWindowedRange)trivialRange {
return VT100GridWindowedRangeMake(VT100GridCoordRangeMake(_coord.x, _coord.y, 0, 0), 0, 0);
}
- (iTermTextExtractor *)extractor {
return [[iTermTextExtractor alloc] initWithDataSource:_textView.dataSource];
}
- (VT100GridCoord)coordFromSelectionEndpoint:(PTYTextViewSelectionEndpoint)endpoint {
iTermSubSelection *sub = _textView.selection.allSubSelections.firstObject;
if (endpoint == kPTYTextViewSelectionEndpointEnd) {
return sub.range.coordRange.end;
} else {
return sub.range.coordRange.start;
}
}
- (BOOL)moveInDirection:(PTYTextViewSelectionExtensionDirection)direction
unit:(PTYTextViewSelectionExtensionUnit)unit {
VT100GridCoord before = _coord;
// Move coord
iTermTextExtractor *extractor = [self extractor];
[extractor restrictToLogicalWindowIncludingCoord:_coord];
VT100GridWindowedRange windowedRange = [self trivialRange];
windowedRange.columnWindow = [extractor logicalWindow];
VT100GridWindowedRange range = [_textView rangeByExtendingRange:windowedRange
endpoint:kPTYTextViewSelectionEndpointStart
direction:direction
extractor:extractor
unit:unit];
_coord = range.coordRange.start;
// Make a new selection
if (_selecting) {
[_textView.selection beginSelectionAt:_start
mode:_mode
resume:NO
append:NO];
[_textView.selection moveSelectionEndpointTo:_coord];
[_textView.selection endLiveSelection];
}
return !VT100GridCoordEquals(before, _coord);
}
@end
Loading
Loading
@@ -38,6 +38,7 @@ typedef struct {
@property(nonatomic, assign) id<iTermCursorDelegate> delegate;
 
+ (iTermCursor *)cursorOfType:(ITermCursorType)theType;
+ (instancetype)copyModeCursor;
 
// No default implementation.
- (void)drawWithRect:(NSRect)rect
Loading
Loading
Loading
Loading
@@ -20,6 +20,9 @@
@interface iTermBoxCursor : iTermCursor
@end
 
@interface iTermCopyModeCursor : iTermCursor
@end
@implementation iTermCursor
 
+ (iTermCursor *)cursorOfType:(ITermCursorType)theType {
Loading
Loading
@@ -38,6 +41,9 @@
}
}
 
+ (instancetype)copyModeCursor {
return [[[iTermCopyModeCursor alloc] init] autorelease];
}
 
- (void)drawWithRect:(NSRect)rect
doubleWidth:(BOOL)doubleWidth
Loading
Loading
@@ -111,6 +117,37 @@
 
@end
 
@implementation iTermCopyModeCursor
- (void)drawWithRect:(NSRect)rect
doubleWidth:(BOOL)doubleWidth
screenChar:(screen_char_t)screenChar
backgroundColor:(NSColor *)backgroundColor
foregroundColor:(NSColor *)foregroundColor
smart:(BOOL)smart
focused:(BOOL)focused
coord:(VT100GridCoord)coord
outline:(BOOL)outline {
const CGFloat heightFraction = 1 / 3.0;
NSRect cursorRect = NSMakeRect(rect.origin.x - rect.size.width,
rect.origin.y,
rect.size.width * 2,
rect.size.height * heightFraction);
NSBezierPath *path = [[[NSBezierPath alloc] init] autorelease];
[path moveToPoint:NSMakePoint(NSMinX(cursorRect), NSMinY(cursorRect))];
[path lineToPoint:NSMakePoint(NSMidX(cursorRect), NSMaxY(cursorRect))];
[path lineToPoint:NSMakePoint(NSMaxX(cursorRect), NSMinY(cursorRect))];
[path lineToPoint:NSMakePoint(NSMinX(cursorRect), NSMinY(cursorRect))];
[[NSColor whiteColor] set];
[path fill];
[[NSColor blackColor] set];
[path stroke];
}
@end
@implementation iTermBoxCursor
 
- (void)drawWithRect:(NSRect)rect
Loading
Loading
Loading
Loading
@@ -18,6 +18,7 @@ extern NSString *const kiTermIndicatorCoprocess;
extern NSString *const kiTermIndicatorAlert;
extern NSString *const kiTermIndicatorAllOutputSuppressed;
extern NSString *const kiTermIndicatorZoomedIn;
extern NSString *const kiTermIndicatorCopyMode;
 
extern CGFloat kiTermIndicatorStandardHeight;
 
Loading
Loading
Loading
Loading
@@ -20,6 +20,7 @@ NSString *const kiTermIndicatorCoprocess = @"kiTermIndicatorCoprocess";
NSString *const kiTermIndicatorAlert = @"kiTermIndicatorAlert";
NSString *const kiTermIndicatorAllOutputSuppressed = @"kiTermIndicatorAllOutputSuppressed";
NSString *const kiTermIndicatorZoomedIn = @"kiTermIndicatorZoomedIn";
NSString *const kiTermIndicatorCopyMode = @"kiTermIndicatorCopyMode";
 
static const NSTimeInterval kFullScreenFlashDuration = 0.3;
static const NSTimeInterval kFlashDuration = 0.3;
Loading
Loading
@@ -74,7 +75,8 @@ CGFloat kiTermIndicatorStandardHeight = 20;
kiTermIndicatorCoprocess: [NSImage imageNamed:@"Coprocess"],
kiTermIndicatorAlert: [NSImage imageNamed:@"Alert"],
kiTermIndicatorAllOutputSuppressed: [NSImage imageNamed:@"SuppressAllOutput"],
kiTermIndicatorZoomedIn: [NSImage imageNamed:@"Zoomed"] };
kiTermIndicatorZoomedIn: [NSImage imageNamed:@"Zoomed"],
kiTermIndicatorCopyMode: [NSImage imageNamed:@"CopyMode"] };
[gIndicatorImages retain];
});
 
Loading
Loading
@@ -118,7 +120,8 @@ CGFloat kiTermIndicatorStandardHeight = 20;
kiTermIndicatorCoprocess,
kiTermIndicatorAlert,
kiTermIndicatorAllOutputSuppressed,
kiTermIndicatorZoomedIn ];
kiTermIndicatorZoomedIn,
kiTermIndicatorCopyMode ];
}
 
- (void)drawInFrame:(NSRect)frame {
Loading
Loading
Loading
Loading
@@ -135,9 +135,9 @@
return;
}
AXUIElementRef element = (__bridge AXUIElementRef)elements.firstObject;
[self openMenuElement:element];
 
if (elements.count > 1) {
[self openMenuElement:element];
DLog(@"Schedule next click...");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self clickThroughElements:[elements subarrayFromIndex:1] completion:completion];
Loading
Loading
Loading
Loading
@@ -110,6 +110,12 @@
// Is the cursor configured to blink?
@property(nonatomic, assign) BOOL cursorBlinking;
 
// Are we in copy mode?
@property(nonatomic, assign) BOOL copyMode;
// Location of the copy-mode cursor
@property(nonatomic, assign) VT100GridCoord copyModeCursorCoord;
// Height of the "excess" region between the last line and the bottom of the view.
@property(nonatomic, assign) double excess;
 
Loading
Loading
Loading
Loading
@@ -417,6 +417,10 @@ typedef struct iTermTextColorContext {
} else {
[self drawCursor:NO];
}
if (self.copyMode) {
[self drawCopyModeCursor];
}
}
 
#pragma mark - Drawing: Background
Loading
Loading
@@ -2208,34 +2212,34 @@ static BOOL iTermTextDrawingHelperIsCharacterDrawable(screen_char_t *c,
 
#pragma mark - Drawing: Cursor
 
- (NSRect)cursorFrame {
const int rowNumber = _cursorCoord.y + _numberOfLines - _gridSize.height;
- (NSRect)frameForCursorAt:(VT100GridCoord)cursorCoord {
const int rowNumber = cursorCoord.y + _numberOfLines - _gridSize.height;
if ([iTermAdvancedSettingsModel fullHeightCursor]) {
const CGFloat height = MAX(_cellSize.height, _cellSizeWithoutSpacing.height);
return NSMakeRect(floor(_cursorCoord.x * _cellSize.width + [iTermAdvancedSettingsModel terminalMargin]),
return NSMakeRect(floor(cursorCoord.x * _cellSize.width + [iTermAdvancedSettingsModel terminalMargin]),
rowNumber * _cellSize.height,
MIN(_cellSize.width, _cellSizeWithoutSpacing.width),
height);
} else {
const CGFloat height = MIN(_cellSize.height, _cellSizeWithoutSpacing.height);
return NSMakeRect(floor(_cursorCoord.x * _cellSize.width + [iTermAdvancedSettingsModel terminalMargin]),
return NSMakeRect(floor(cursorCoord.x * _cellSize.width + [iTermAdvancedSettingsModel terminalMargin]),
rowNumber * _cellSize.height + MAX(0, round((_cellSize.height - _cellSizeWithoutSpacing.height) / 2.0)),
MIN(_cellSize.width, _cellSizeWithoutSpacing.width),
height);
}
}
 
- (NSRect)cursorFrameIncludingDoubleWidthAdjustment {
screen_char_t *theLine = [self.delegate drawingHelperLineAtScreenIndex:_cursorCoord.y];
BOOL isDoubleWidth;
[self charForCursorAtColumn:_cursorCoord.x
inLine:theLine
doubleWidth:&isDoubleWidth];
NSRect rect = [self cursorFrame];
if (isDoubleWidth) {
rect.size.width *= 2;
}
return rect;
- (NSRect)cursorFrame {
return [self frameForCursorAt:_cursorCoord];
}
- (void)drawCopyModeCursor {
iTermCursor *cursor = [iTermCursor copyModeCursor];
cursor.delegate = self;
[self reallyDrawCursor:cursor
at:VT100GridCoordMake(_copyModeCursorCoord.x, _copyModeCursorCoord.y - _numberOfScrollbackLines)
outline:NO];
}
 
- (void)drawCursor:(BOOL)outline {
Loading
Loading
@@ -2248,51 +2252,10 @@ static BOOL iTermTextDrawingHelperIsCharacterDrawable(screen_char_t *c,
}
 
if ([self shouldDrawCursor]) {
// Get the character that's under the cursor.
screen_char_t *theLine = [self.delegate drawingHelperLineAtScreenIndex:_cursorCoord.y];
BOOL isDoubleWidth;
screen_char_t screenChar = [self charForCursorAtColumn:_cursorCoord.x
inLine:theLine
doubleWidth:&isDoubleWidth];
// Update the "find cursor" view.
[self.delegate drawingHelperUpdateFindCursorView];
// Get the color of the cursor.
NSColor *cursorColor;
if (outline) {
cursorColor = [_colorMap colorForKey:kColorMapBackground];
} else {
cursorColor = [self backgroundColorForCursor];
}
NSRect rect = [self cursorFrame];
if (isDoubleWidth) {
rect.size.width *= 2;
}
iTermCursor *cursor = [iTermCursor cursorOfType:_cursorType];
cursor.delegate = self;
NSRect rect = [self reallyDrawCursor:cursor at:_cursorCoord outline:outline];
 
NSColor *cursorTextColor;
if (_reverseVideo) {
cursorTextColor = [_colorMap colorForKey:kColorMapBackground];
} else {
cursorTextColor = [_delegate drawingHelperColorForCode:ALTSEM_CURSOR
green:0
blue:0
colorMode:ColorModeAlternate
bold:NO
faint:NO
isBackground:NO];
}
[cursor drawWithRect:rect
doubleWidth:isDoubleWidth
screenChar:screenChar
backgroundColor:cursorColor
foregroundColor:cursorTextColor
smart:_useSmartCursorColor
focused:((_isInKeyWindow && _textViewIsActiveSession) || _shouldDrawFilledInCursor)
coord:_cursorCoord
outline:outline];
if (_showSearchingCursor) {
NSImage *image = [NSImage imageNamed:@"SearchCursor"];
if (image) {
Loading
Loading
@@ -2319,6 +2282,58 @@ static BOOL iTermTextDrawingHelperIsCharacterDrawable(screen_char_t *c,
_oldCursorPosition = _cursorCoord;
}
 
- (NSRect)reallyDrawCursor:(iTermCursor *)cursor at:(VT100GridCoord)cursorCoord outline:(BOOL)outline {
// Get the character that's under the cursor.
screen_char_t *theLine;
if (cursorCoord.y >= 0) {
theLine = [self.delegate drawingHelperLineAtScreenIndex:cursorCoord.y];
} else {
theLine = [self.delegate drawingHelperLineAtIndex:cursorCoord.y + _numberOfScrollbackLines];
}
BOOL isDoubleWidth;
screen_char_t screenChar = [self charForCursorAtColumn:cursorCoord.x
inLine:theLine
doubleWidth:&isDoubleWidth];
// Update the "find cursor" view.
[self.delegate drawingHelperUpdateFindCursorView];
// Get the color of the cursor.
NSColor *cursorColor;
if (outline) {
cursorColor = [_colorMap colorForKey:kColorMapBackground];
} else {
cursorColor = [self backgroundColorForCursor];
}
NSRect rect = [self frameForCursorAt:cursorCoord];
if (isDoubleWidth) {
rect.size.width *= 2;
}
NSColor *cursorTextColor;
if (_reverseVideo) {
cursorTextColor = [_colorMap colorForKey:kColorMapBackground];
} else {
cursorTextColor = [_delegate drawingHelperColorForCode:ALTSEM_CURSOR
green:0
blue:0
colorMode:ColorModeAlternate
bold:NO
faint:NO
isBackground:NO];
}
[cursor drawWithRect:rect
doubleWidth:isDoubleWidth
screenChar:screenChar
backgroundColor:cursorColor
foregroundColor:cursorTextColor
smart:_useSmartCursorColor
focused:((_isInKeyWindow && _textViewIsActiveSession) || _shouldDrawFilledInCursor)
coord:cursorCoord
outline:outline];
return rect;
}
#pragma mark - Text Run Construction
 
- (NSRange)underlinedRangeOnLine:(long long)row {
Loading
Loading
@@ -2430,7 +2445,7 @@ static BOOL iTermTextDrawingHelperIsCharacterDrawable(screen_char_t *c,
column >= 0 &&
row >= 0 &&
row < height);
DLog(@"shouldDrawCursor: hasMarkedText=%d, cursorVisible=%d, showCursor=%d, column=%d, row=%d, "
DLog(@"shouldDrawCursor: hasMarkedText=%d, cursorVisible=%d, showCursor=%d, column=%d, row=%d"
@"width=%d, height=%d. Result=%@",
(int)[self hasMarkedText], (int)_cursorVisible, (int)shouldShowCursor, column, row,
width, height, @(result));
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment