mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-11 15:37:29 +02:00
Merge pull request #1552 from ychin/fix-writing-tools-and-services-text-replacement
Fix Writing Tools integration and fix up Services integration with texts
This commit is contained in:
+122
-140
@@ -1380,160 +1380,142 @@ static struct specialkey
|
||||
return eval;
|
||||
}
|
||||
|
||||
/// Extracts the text currently selected in visual mode, and returns it.
|
||||
///
|
||||
/// @return the string representing the selected text, or NULL if failure.
|
||||
static char_u *extractSelectedText(void)
|
||||
- (BOOL)hasSelectedText
|
||||
{
|
||||
// Note: Most of the functionality in Vim that allows for extracting useful
|
||||
// text from a selection are in the register & clipboard utility functions.
|
||||
// Unfortunately, most of those functions would actually send the text to
|
||||
// the system clipboard, which we don't want (since we just want to extract
|
||||
// the text instead of polluting the system clipboard). We don't want to
|
||||
// refactor upstream Vim code too much to avoid merge pains later, so we
|
||||
// duplicate a fair bit of the code from the functions below.
|
||||
|
||||
if (!(VIsual_active && (State & MODE_NORMAL))) {
|
||||
// This only works when we are in visual mode and have stuff to select.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Step 1: Find a register to yank the selection to. If we don't do this we
|
||||
// have to duplicate a lot of code in op_yank(). We save it off to a backup
|
||||
// first so we can restore it later to avoid polluting the registers.
|
||||
|
||||
// Just use the yank / '0' register as it makes sense, but it doesn't
|
||||
// really matter.
|
||||
yankreg_T *target_reg = get_y_register(0);
|
||||
|
||||
// Move the contents to the backup without doing memory allocs.
|
||||
yankreg_T backup_reg = *target_reg;
|
||||
target_reg->y_array = NULL;
|
||||
target_reg->y_size = 0;
|
||||
|
||||
// Step 2: Preserve the local states, and then invoke yank.
|
||||
// Note: These were copied from clip_get_selection() in clipboard.c
|
||||
yankreg_T *old_y_previous, *old_y_current;
|
||||
pos_T old_cursor;
|
||||
pos_T old_visual;
|
||||
int old_visual_mode;
|
||||
colnr_T old_curswant;
|
||||
int old_set_curswant;
|
||||
pos_T old_op_start, old_op_end;
|
||||
oparg_T oa;
|
||||
cmdarg_T ca;
|
||||
|
||||
// Avoid triggering autocmds such as TextYankPost.
|
||||
block_autocmds();
|
||||
|
||||
// Yank the selected text into the target register.
|
||||
old_y_previous = get_y_previous();
|
||||
old_y_current = get_y_current();
|
||||
old_cursor = curwin->w_cursor;
|
||||
old_curswant = curwin->w_curswant;
|
||||
old_set_curswant = curwin->w_set_curswant;
|
||||
old_op_start = curbuf->b_op_start;
|
||||
old_op_end = curbuf->b_op_end;
|
||||
old_visual = VIsual;
|
||||
old_visual_mode = VIsual_mode;
|
||||
clear_oparg(&oa);
|
||||
oa.regname = '0'; // Use the '0' (yank) register. We will restore it later to avoid pollution.
|
||||
oa.op_type = OP_YANK;
|
||||
CLEAR_FIELD(ca);
|
||||
ca.oap = &oa;
|
||||
ca.cmdchar = 'y';
|
||||
ca.count1 = 1;
|
||||
ca.retval = CA_NO_ADJ_OP_END;
|
||||
do_pending_operator(&ca, 0, TRUE);
|
||||
|
||||
// Step 3: Extract the text from the yank ('0') register.
|
||||
char_u *str = get_reg_contents(0, 0);
|
||||
|
||||
// Step 4: Clean up the yank register, and restore it back.
|
||||
set_y_current(target_reg); // should not be necessary as it's done in do_pending_operator above (since regname was set to 0), but just to be safe and verbose in intention.
|
||||
free_yank_all();
|
||||
*target_reg = backup_reg;
|
||||
|
||||
// Step 5: Restore all the loose states that were modified during yank.
|
||||
// Note: These were copied from clip_get_selection() in clipboard.c
|
||||
set_y_previous(old_y_previous);
|
||||
set_y_current(old_y_current);
|
||||
curwin->w_cursor = old_cursor;
|
||||
changed_cline_bef_curs(); // need to update w_virtcol et al
|
||||
curwin->w_curswant = old_curswant;
|
||||
curwin->w_set_curswant = old_set_curswant;
|
||||
curbuf->b_op_start = old_op_start;
|
||||
curbuf->b_op_end = old_op_end;
|
||||
VIsual = old_visual;
|
||||
VIsual_mode = old_visual_mode;
|
||||
|
||||
unblock_autocmds();
|
||||
|
||||
return str;
|
||||
return (VIsual_active && (State & MODE_NORMAL));
|
||||
}
|
||||
|
||||
/// Extract the currently selected text (in visual mode) and send that to the
|
||||
/// provided pasteboard.
|
||||
- (BOOL)selectedTextToPasteboard:(byref NSPasteboard *)pboard
|
||||
{
|
||||
if (VIsual_active && (State & MODE_NORMAL)) {
|
||||
// If there is no pasteboard, just return YES to indicate that there is
|
||||
// text to copy.
|
||||
if (!pboard)
|
||||
return YES;
|
||||
|
||||
char_u *str = extractSelectedText();
|
||||
if (!str)
|
||||
return NO;
|
||||
|
||||
if (output_conv.vc_type != CONV_NONE) {
|
||||
char_u *conv_str = string_convert(&output_conv, str, NULL);
|
||||
if (conv_str) {
|
||||
vim_free(str);
|
||||
str = conv_str;
|
||||
}
|
||||
}
|
||||
|
||||
NSString *string = [[NSString alloc] initWithUTF8String:(char*)str];
|
||||
|
||||
NSArray *types = [NSArray arrayWithObject:NSPasteboardTypeString];
|
||||
[pboard declareTypes:types owner:nil];
|
||||
BOOL ok = [pboard setString:string forType:NSPasteboardTypeString];
|
||||
|
||||
[string release];
|
||||
vim_free(str);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
/// Returns the currently selected text. We should consolidate this with
|
||||
/// selectedTextToPasteboard: above when we have time. (That function has a
|
||||
/// fast path just to query whether selected text exists)
|
||||
/// Returns the currently selected text.
|
||||
- (NSString *)selectedText
|
||||
{
|
||||
if (VIsual_active && (State & MODE_NORMAL)) {
|
||||
char_u *str = extractSelectedText();
|
||||
if (!str)
|
||||
return nil;
|
||||
// This is basically doing the following:
|
||||
// - join(getregion(getpos("."), getpos("v"), { type: visualmode() }),"\n")
|
||||
// - Add extra "\n" if we have a linewise selection
|
||||
|
||||
if (output_conv.vc_type != CONV_NONE) {
|
||||
char_u *conv_str = string_convert(&output_conv, str, NULL);
|
||||
if (conv_str) {
|
||||
vim_free(str);
|
||||
str = conv_str;
|
||||
// Call getpos()
|
||||
typval_T pos1, pos2;
|
||||
{
|
||||
typval_T arg_posmark;
|
||||
init_tv(&arg_posmark);
|
||||
arg_posmark.v_type = VAR_STRING;
|
||||
|
||||
arg_posmark.vval.v_string = (char_u*)".";
|
||||
typval_T args1[1] = { arg_posmark };
|
||||
f_getpos(args1, &pos1);
|
||||
if (pos1.v_type != VAR_LIST)
|
||||
return nil;
|
||||
|
||||
arg_posmark.vval.v_string = (char_u*)"v";
|
||||
typval_T args2[1] = { arg_posmark };
|
||||
f_getpos(args2, &pos2);
|
||||
if (pos2.v_type != VAR_LIST) {
|
||||
list_unref(pos1.vval.v_list);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
NSString *string = [[NSString alloc] initWithUTF8String:(char*)str];
|
||||
vim_free(str);
|
||||
return [string autorelease];
|
||||
// Call getregion()
|
||||
typval_T arg_opts;
|
||||
init_tv(&arg_opts);
|
||||
arg_opts.v_type = VAR_DICT;
|
||||
arg_opts.vval.v_dict = dict_alloc();
|
||||
arg_opts.vval.v_dict->dv_refcount += 1;
|
||||
|
||||
char_u visualmode[2] = { VIsual_mode, '\0' };
|
||||
dict_add_string(arg_opts.vval.v_dict, "type", visualmode);
|
||||
|
||||
typval_T args[3] = { pos1, pos2, arg_opts };
|
||||
typval_T regionLines;
|
||||
f_getregion(args, ®ionLines);
|
||||
|
||||
// Join the results
|
||||
NSMutableArray *returnLines = [NSMutableArray array];
|
||||
if (regionLines.v_type == VAR_LIST) {
|
||||
list_T *lines = regionLines.vval.v_list;
|
||||
for (listitem_T *item = lines->lv_first; item != NULL; item = item->li_next) {
|
||||
if (item->li_tv.v_type == VAR_STRING) {
|
||||
char_u *str = item->li_tv.vval.v_string;
|
||||
if (output_conv.vc_type != CONV_NONE) {
|
||||
char_u *conv_str = string_convert(&output_conv, str, NULL);
|
||||
if (conv_str) {
|
||||
[returnLines addObject:[NSString stringWithUTF8String:(char*)conv_str]];
|
||||
vim_free(conv_str);
|
||||
}
|
||||
} else {
|
||||
[returnLines addObject:[NSString stringWithUTF8String:(char*)str]];
|
||||
}
|
||||
}
|
||||
}
|
||||
list_unref(lines);
|
||||
}
|
||||
dict_unref(arg_opts.vval.v_dict);
|
||||
list_unref(pos1.vval.v_list);
|
||||
list_unref(pos2.vval.v_list);
|
||||
|
||||
if (VIsual_mode == 'V')
|
||||
[returnLines addObject:@""]; // need trailing endline for linewise
|
||||
return [returnLines componentsJoinedByString:@"\n"];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
/// Replace the selected text in visual mode with the new suppiled one.
|
||||
- (oneway void)replaceSelectedText:(in bycopy NSString *)text
|
||||
{
|
||||
if (VIsual_active && (State & MODE_NORMAL)) {
|
||||
// The only real way Vim has in doing this consistently is to use the
|
||||
// register put functionality as there is no generic API for this.
|
||||
// We find an arbitrary register ('0'), back it up, replace it with our
|
||||
// own content, paste it in, then restore the register to old value.
|
||||
yankreg_T *target_reg = get_y_register(0);
|
||||
yankreg_T backup_reg = *target_reg;
|
||||
target_reg->y_array = NULL;
|
||||
target_reg->y_size = 0;
|
||||
|
||||
// If selection is blockwise, we try to match it. Only do it if input
|
||||
// and selected text have same number of lines, as otherwise it could
|
||||
// be awkward.
|
||||
int yank_type = MAUTO;
|
||||
char_u *vimtext = [text vimStringSave];
|
||||
if (VIsual_mode == Ctrl_V) {
|
||||
long text_lines = string_count(vimtext, (char_u*)"\n", FALSE) + 1;
|
||||
|
||||
linenr_T v1 = VIsual.lnum;
|
||||
linenr_T v2 = curwin->w_cursor.lnum;
|
||||
long num_lines = v1 > v2 ? v1 - v2 + 1 : v2 - v1 + 1;
|
||||
|
||||
if (text_lines == num_lines)
|
||||
yank_type = MBLOCK;
|
||||
}
|
||||
write_reg_contents_ex('0', vimtext, -1, FALSE, yank_type, -1);
|
||||
vim_free(vimtext);
|
||||
|
||||
oparg_T oap;
|
||||
CLEAR_FIELD(oap);
|
||||
oap.regname = '0';
|
||||
|
||||
cmdarg_T cap;
|
||||
CLEAR_FIELD(cap);
|
||||
cap.oap = &oap;
|
||||
cap.cmdchar = 'P';
|
||||
cap.count1 = 1;
|
||||
|
||||
nv_put(&cap);
|
||||
|
||||
// Clean up the temporary register, and restore the old state.
|
||||
yankreg_T *old_y_current = get_y_current();
|
||||
set_y_current(target_reg);
|
||||
free_yank_all();
|
||||
set_y_current(old_y_current);
|
||||
*target_reg = backup_reg;
|
||||
|
||||
// nv_put does not trigger a redraw command as it's done on a higher
|
||||
// level, so just do a manual one here to make sure it's done.
|
||||
[self redrawScreen];
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the provided mouse screen position is on a visually
|
||||
/// selected range of text.
|
||||
///
|
||||
|
||||
@@ -648,8 +648,7 @@ static void grid_free(Grid *grid) {
|
||||
|
||||
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
// We are not currently replacementRange right now.
|
||||
[helper insertText:string];
|
||||
[helper insertText:string replacementRange:replacementRange];
|
||||
}
|
||||
|
||||
- (void)doCommandBySelector:(SEL)selector
|
||||
@@ -1992,7 +1991,7 @@ static void rowColFromUtfRange(const Grid* grid, NSRange range,
|
||||
// top of said selection and if so, show definition of that instead.
|
||||
MMVimController *vc = [self vimController];
|
||||
id<MMBackendProtocol> backendProxy = [vc backendProxy];
|
||||
if ([backendProxy selectedTextToPasteboard:nil]) {
|
||||
if ([backendProxy hasSelectedText]) {
|
||||
int selRow = 0, selCol = 0;
|
||||
const BOOL isMouseInSelection = [backendProxy mouseScreenposIsSelection:row column:col selRow:&selRow selCol:&selCol];
|
||||
|
||||
|
||||
@@ -724,7 +724,7 @@
|
||||
|
||||
- (void)insertText:(id)string
|
||||
{
|
||||
[helper insertText:string];
|
||||
[helper insertText:string replacementRange:NSMakeRange(0, 0)];
|
||||
}
|
||||
|
||||
- (void)doCommandBySelector:(SEL)selector
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
- (NSColor *)insertionPointColor;
|
||||
|
||||
- (void)keyDown:(NSEvent *)event;
|
||||
- (void)insertText:(id)string;
|
||||
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange;
|
||||
- (void)doCommandBySelector:(SEL)selector;
|
||||
- (void)scrollWheel:(NSEvent *)event;
|
||||
- (void)mouseDown:(NSEvent *)event;
|
||||
|
||||
@@ -221,7 +221,7 @@ KeyboardInputSourcesEqual(TISInputSourceRef a, TISInputSourceRef b)
|
||||
currentEvent = nil;
|
||||
}
|
||||
|
||||
- (void)insertText:(id)string
|
||||
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
if ([self hasMarkedText]) {
|
||||
[self sendMarkedText:nil position:0];
|
||||
@@ -241,6 +241,20 @@ KeyboardInputSourcesEqual(TISInputSourceRef a, TISInputSourceRef b)
|
||||
if ([string isKindOfClass:[NSAttributedString class]])
|
||||
string = [string string];
|
||||
|
||||
if (replacementRange.length > 0)
|
||||
{
|
||||
// Replacement range is a concept we don't really have a way to fulfill
|
||||
// as we don't have proper access to the underlying text storage. This
|
||||
// should usually be triggered when we have selected text though, and
|
||||
// so we simply ask Vim to replace the current selection with the new
|
||||
// text, and it should hopefully work.
|
||||
// Only known way of this being called is Apple Intelligence Writing
|
||||
// Tools.
|
||||
MMVimController *vc = [self vimController];
|
||||
[vc replaceSelectedText:string];
|
||||
return;
|
||||
}
|
||||
|
||||
//int len = [string length];
|
||||
//ASLogDebug(@"len=%d char[0]=%#x char[1]=%#x string='%@'", [string length],
|
||||
// [string characterAtIndex:0],
|
||||
|
||||
@@ -92,6 +92,9 @@
|
||||
- (NSString *)evaluateVimExpression:(NSString *)expr;
|
||||
- (id)evaluateVimExpressionCocoa:(NSString *)expr
|
||||
errorString:(NSString **)errstr;
|
||||
- (BOOL)hasSelectedText;
|
||||
- (NSString *)selectedText;
|
||||
- (void)replaceSelectedText:(NSString *)text;
|
||||
- (void)processInputQueue:(NSArray *)queue;
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12_2
|
||||
- (NSTouchBar *)makeTouchBar;
|
||||
|
||||
@@ -533,6 +533,49 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
return eval;
|
||||
}
|
||||
|
||||
- (BOOL)hasSelectedText
|
||||
{
|
||||
BOOL hasSelectedText = NO;
|
||||
if (backendProxy) {
|
||||
@try {
|
||||
hasSelectedText = [backendProxy hasSelectedText];
|
||||
}
|
||||
@catch (NSException *ex) {
|
||||
ASLogDebug(@"hasSelectedText: failed: pid=%d reason=%@",
|
||||
pid, ex);
|
||||
}
|
||||
}
|
||||
return hasSelectedText;
|
||||
}
|
||||
|
||||
- (NSString *)selectedText
|
||||
{
|
||||
NSString *selectedText = nil;
|
||||
if (backendProxy) {
|
||||
@try {
|
||||
selectedText = [backendProxy selectedText];
|
||||
}
|
||||
@catch (NSException *ex) {
|
||||
ASLogDebug(@"selectedText: failed: pid=%d reason=%@",
|
||||
pid, ex);
|
||||
}
|
||||
}
|
||||
return selectedText;
|
||||
}
|
||||
|
||||
- (void)replaceSelectedText:(NSString *)text
|
||||
{
|
||||
if (backendProxy) {
|
||||
@try {
|
||||
[backendProxy replaceSelectedText:text];
|
||||
}
|
||||
@catch (NSException *ex) {
|
||||
ASLogDebug(@"replaceSelectedText: failed: pid=%d reason=%@",
|
||||
pid, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (id)backendProxy
|
||||
{
|
||||
return backendProxy;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
@class MMVimView;
|
||||
|
||||
@interface MMWindowController : NSWindowController<
|
||||
NSWindowDelegate
|
||||
NSWindowDelegate, NSServicesMenuRequestor
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
|
||||
, NSMenuItemValidation
|
||||
#endif
|
||||
|
||||
@@ -86,7 +86,6 @@
|
||||
keepOnScreen:(BOOL)onScreen;
|
||||
- (NSSize)constrainContentSizeToScreenSize:(NSSize)contentSize;
|
||||
- (NSRect)constrainFrame:(NSRect)frame;
|
||||
- (BOOL)askBackendForSelectedText:(NSPasteboard *)pb;
|
||||
- (void)updateTablineSeparator;
|
||||
- (void)hideTablineSeparator:(BOOL)hide;
|
||||
- (void)doFindNext:(BOOL)next;
|
||||
@@ -1642,7 +1641,7 @@
|
||||
- (id)validRequestorForSendType:(NSString *)sendType
|
||||
returnType:(NSString *)returnType
|
||||
{
|
||||
const BOOL sendOk = (([sendType isEqual:NSPasteboardTypeString] && [self askBackendForSelectedText:nil])
|
||||
const BOOL sendOk = (([sendType isEqual:NSPasteboardTypeString] && [self.vimController hasSelectedText])
|
||||
|| [sendType length] == 0);
|
||||
const BOOL returnOk = ([returnType isEqual:NSPasteboardTypeString] || [returnType length] == 0);
|
||||
if (sendOk && returnOk)
|
||||
@@ -1662,7 +1661,14 @@
|
||||
// We should really be fine here since we already checked the types in
|
||||
// validRequestsForSendType: above.
|
||||
(void)types;
|
||||
return [self askBackendForSelectedText:pboard];
|
||||
|
||||
NSString *string = [vimController selectedText];
|
||||
if (string != nil) {
|
||||
NSArray *types = [NSArray arrayWithObject:NSPasteboardTypeString];
|
||||
[pboard declareTypes:types owner:nil];
|
||||
return [pboard setString:string forType:NSPasteboardTypeString];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
/// Called by the OS when it tries to update the selection. This could happen
|
||||
@@ -1672,9 +1678,8 @@
|
||||
// Replace the current selection with the text on the pasteboard.
|
||||
NSArray *types = [pboard types];
|
||||
if ([types containsObject:NSPasteboardTypeString]) {
|
||||
NSString *input = [NSString stringWithFormat:@"s%@",
|
||||
[pboard stringForType:NSPasteboardTypeString]];
|
||||
[vimController addVimInput:input];
|
||||
NSString *input = [pboard stringForType:NSPasteboardTypeString];
|
||||
[vimController replaceSelectedText:input];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -1986,30 +1991,6 @@
|
||||
return [decoratedWindow frameRectForContentRect:contentRect];
|
||||
}
|
||||
|
||||
/// Ask Vim to fill in the pasteboard with the currently selected text in visual mode.
|
||||
- (BOOL)askBackendForSelectedText:(NSPasteboard *)pb
|
||||
{
|
||||
// This could potentially be done via evaluateExpression by yanking the
|
||||
// selection, then returning the results via getreg('@') and restoring the
|
||||
// register. Using a dedicated API is probably a little safer (e.g. it
|
||||
// prevents TextYankPost autocmd's from triggering) and efficient
|
||||
// and hence this is what we use for now.
|
||||
BOOL reply = NO;
|
||||
id backendProxy = [vimController backendProxy];
|
||||
|
||||
if (backendProxy) {
|
||||
@try {
|
||||
reply = [backendProxy selectedTextToPasteboard:pb];
|
||||
}
|
||||
@catch (NSException *ex) {
|
||||
ASLogDebug(@"selectedTextToPasteboard: failed: pid=%d reason=%@",
|
||||
[vimController pid], ex);
|
||||
}
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
- (void)updateTablineSeparator
|
||||
{
|
||||
BOOL tablineVisible = ![[vimView tabline] isHidden];
|
||||
|
||||
+2
-1
@@ -192,8 +192,9 @@ typedef NSString* NSAttributedStringKey;
|
||||
- (NSString *)evaluateExpression:(in bycopy NSString *)expr;
|
||||
- (id)evaluateExpressionCocoa:(in bycopy NSString *)expr
|
||||
errorString:(out bycopy NSString **)errstr;
|
||||
- (BOOL)selectedTextToPasteboard:(byref NSPasteboard *)pboard;
|
||||
- (BOOL)hasSelectedText;
|
||||
- (NSString *)selectedText;
|
||||
- (oneway void)replaceSelectedText:(in bycopy NSString *)text;
|
||||
- (BOOL)mouseScreenposIsSelection:(int)row column:(int)column selRow:(byref int *)startRow selCol:(byref int *)startCol;
|
||||
- (oneway void)acknowledgeConnection;
|
||||
@end
|
||||
|
||||
@@ -362,17 +362,22 @@ static BOOL vimProcessInputBlocked = NO;
|
||||
/// Send a single key to MacVim via event handling system.
|
||||
- (void)sendKeyToVim:(NSString*)chars withMods:(int)mods {
|
||||
NSApplication* app = [NSApplication sharedApplication];
|
||||
|
||||
NSString *modChars = chars;
|
||||
if (mods & NSEventModifierFlagControl) {
|
||||
unichar ch = [chars characterAtIndex:0] & ~0x60;
|
||||
modChars = [NSString stringWithCharacters:&ch length:1];
|
||||
}
|
||||
NSEvent* keyEvent = [NSEvent keyEventWithType:NSEventTypeKeyDown
|
||||
location:NSMakePoint(50, 50)
|
||||
modifierFlags:mods
|
||||
timestamp:100
|
||||
windowNumber:[[NSApp mainWindow] windowNumber]
|
||||
context:0
|
||||
characters:chars
|
||||
characters:modChars
|
||||
charactersIgnoringModifiers:chars
|
||||
isARepeat:NO
|
||||
keyCode:0];
|
||||
|
||||
[app postEvent:keyEvent atStart:NO];
|
||||
}
|
||||
|
||||
@@ -1384,4 +1389,74 @@ do { \
|
||||
XCTAssertTrue(NSPointInRect(winController.window.frame.origin, NSScreen.screens[0].frame));
|
||||
}
|
||||
|
||||
#pragma mark Vim IPC
|
||||
|
||||
/// Test the selected text related IPC APIs
|
||||
- (void)testIPCSelectedText {
|
||||
[self createTestVimWindow];
|
||||
[self sendStringToVim:@":put =['abcd', 'efgh', 'ijkl']\nggdd" withMods:0];
|
||||
[self waitForEventHandlingAndVimProcess];
|
||||
|
||||
MMAppController *app = MMAppController.sharedInstance;
|
||||
MMVimController *vc = app.keyVimController;
|
||||
|
||||
// Set up register
|
||||
[self sendStringToVim:@"ggyy" withMods:0];
|
||||
[self waitForEventHandlingAndVimProcess];
|
||||
NSString *regcontents = [vc evaluateVimExpression:@"getreg()"];
|
||||
XCTAssertEqualObjects(regcontents, @"abcd\n");
|
||||
|
||||
// Get selected texts in visual mode
|
||||
XCTAssertFalse([vc hasSelectedText]);
|
||||
XCTAssertNil([vc selectedText]);
|
||||
[self sendStringToVim:@"lvjl" withMods:0];
|
||||
[self waitForEventHandlingAndVimProcess];
|
||||
XCTAssertTrue([vc hasSelectedText]);
|
||||
XCTAssertEqualObjects([vc selectedText], @"bcd\nefg");
|
||||
|
||||
// Get selected texts in visual line mode
|
||||
[self sendStringToVim:@"V" withMods:0];
|
||||
[self waitForEventHandlingAndVimProcess];
|
||||
XCTAssertTrue([vc hasSelectedText]);
|
||||
XCTAssertEqualObjects([vc selectedText], @"abcd\nefgh\n");
|
||||
|
||||
// Get selected texts in visual block mode
|
||||
[self sendKeyToVim:@"v" withMods:NSEventModifierFlagControl];
|
||||
[self waitForEventHandlingAndVimProcess];
|
||||
XCTAssertTrue([vc hasSelectedText]);
|
||||
XCTAssertEqualObjects([vc selectedText], @"bc\nfg");
|
||||
|
||||
// Set selected texts in visual block mode
|
||||
NSString *changedtick = [vc evaluateVimExpression:@"b:changedtick"];
|
||||
[vc replaceSelectedText:@"xyz\n1234"];
|
||||
NSString *changedtick2 = [vc evaluateVimExpression:@"b:changedtick"];
|
||||
XCTAssertEqualObjects([vc evaluateVimExpression:@"getline(1)"], @"axyz d");
|
||||
XCTAssertEqualObjects([vc evaluateVimExpression:@"getline(2)"], @"e1234h");
|
||||
XCTAssertEqualObjects([vc evaluateVimExpression:@"getline(3)"], @"ijkl");
|
||||
XCTAssertNotEqualObjects(changedtick, changedtick2);
|
||||
|
||||
// Make sure replacing texts when nothing is selected won't set anything
|
||||
[vc replaceSelectedText:@"foobar"];
|
||||
NSString *changedtick3 = [vc evaluateVimExpression:@"b:changedtick"];
|
||||
XCTAssertEqualObjects(changedtick2, changedtick3);
|
||||
|
||||
// Select in visual block again but send a different number of lines, make sure we intentionaly won't treat it as block text
|
||||
[self sendStringToVim:@"ggjjvll" withMods:0];
|
||||
[self sendKeyToVim:@"v" withMods:NSEventModifierFlagControl];
|
||||
[self waitForEventHandlingAndVimProcess];
|
||||
[vc replaceSelectedText:@"xyz\n1234\n"]; // ending in newline means it gets interpreted as line-wise
|
||||
XCTAssertEqualObjects([vc evaluateVimExpression:@"getline(1)"], @"axyz d");
|
||||
XCTAssertEqualObjects([vc evaluateVimExpression:@"getline(2)"], @"e1234h");
|
||||
XCTAssertEqualObjects([vc evaluateVimExpression:@"getline(3)"], @"xyz");
|
||||
XCTAssertEqualObjects([vc evaluateVimExpression:@"getline(4)"], @"1234");
|
||||
XCTAssertEqualObjects([vc evaluateVimExpression:@"getline(5)"], @"l");
|
||||
|
||||
// Make sure registers didn't get stomped (internally the implementation uses register and manually restores it)
|
||||
regcontents = [[app keyVimController] evaluateVimExpression:@"getreg()"];
|
||||
XCTAssertEqualObjects(regcontents, @"abcd\n");
|
||||
|
||||
[self sendStringToVim:@":set nomodified\n" withMods:0];
|
||||
[self waitForEventHandlingAndVimProcess];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+2
-4
@@ -72,10 +72,8 @@ static void f_getenv(typval_T *argvars, typval_T *rettv);
|
||||
static void f_getfontname(typval_T *argvars, typval_T *rettv);
|
||||
static void f_getjumplist(typval_T *argvars, typval_T *rettv);
|
||||
static void f_getpid(typval_T *argvars, typval_T *rettv);
|
||||
static void f_getpos(typval_T *argvars, typval_T *rettv);
|
||||
static void f_getreg(typval_T *argvars, typval_T *rettv);
|
||||
static void f_getreginfo(typval_T *argvars, typval_T *rettv);
|
||||
static void f_getregion(typval_T *argvars, typval_T *rettv);
|
||||
static void f_getregionpos(typval_T *argvars, typval_T *rettv);
|
||||
static void f_getregtype(typval_T *argvars, typval_T *rettv);
|
||||
static void f_gettagstack(typval_T *argvars, typval_T *rettv);
|
||||
@@ -5758,7 +5756,7 @@ f_getcursorcharpos(typval_T *argvars, typval_T *rettv)
|
||||
/*
|
||||
* "getpos(string)" function
|
||||
*/
|
||||
static void
|
||||
void
|
||||
f_getpos(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
|
||||
@@ -5949,7 +5947,7 @@ getregionpos(
|
||||
/*
|
||||
* "getregion()" function
|
||||
*/
|
||||
static void
|
||||
void
|
||||
f_getregion(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
pos_T p1, p2;
|
||||
|
||||
+1
-2
@@ -112,7 +112,6 @@ static void nv_record(cmdarg_T *cap);
|
||||
static void nv_at(cmdarg_T *cap);
|
||||
static void nv_halfpage(cmdarg_T *cap);
|
||||
static void nv_join(cmdarg_T *cap);
|
||||
static void nv_put(cmdarg_T *cap);
|
||||
static void nv_put_opt(cmdarg_T *cap, int fix_indent);
|
||||
static void nv_open(cmdarg_T *cap);
|
||||
#ifdef FEAT_NETBEANS_INTG
|
||||
@@ -7339,7 +7338,7 @@ nv_join(cmdarg_T *cap)
|
||||
/*
|
||||
* "P", "gP", "p" and "gp" commands.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
nv_put(cmdarg_T *cap)
|
||||
{
|
||||
nv_put_opt(cap, FALSE);
|
||||
|
||||
@@ -30,5 +30,7 @@ long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, typval_T *
|
||||
|
||||
// MacVim only
|
||||
void f_getcurpos(typval_T *argvars, typval_T *rettv);
|
||||
void f_getpos(typval_T *argvars, typval_T *rettv);
|
||||
void f_getregion(typval_T *argvars, typval_T *rettv);
|
||||
|
||||
/* vim: set ft=c : */
|
||||
|
||||
@@ -33,4 +33,8 @@ void may_start_select(int c);
|
||||
int unadjust_for_sel(void);
|
||||
int unadjust_for_sel_inner(pos_T *pp);
|
||||
void set_cursor_for_append_to_line(void);
|
||||
|
||||
// MacVim only
|
||||
void nv_put(cmdarg_T *cap);
|
||||
|
||||
/* vim: set ft=c : */
|
||||
|
||||
Reference in New Issue
Block a user