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:
Yee Cheng Chin
2025-02-12 05:42:34 -08:00
committed by GitHub
15 changed files with 287 additions and 186 deletions
+122 -140
View File
@@ -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, &regionLines);
// 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.
///
+2 -3
View File
@@ -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];
+1 -1
View File
@@ -724,7 +724,7 @@
- (void)insertText:(id)string
{
[helper insertText:string];
[helper insertText:string replacementRange:NSMakeRange(0, 0)];
}
- (void)doCommandBySelector:(SEL)selector
+1 -1
View File
@@ -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;
+15 -1
View File
@@ -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],
+3
View File
@@ -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;
+43
View File
@@ -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;
+1 -1
View File
@@ -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
+11 -30
View File
@@ -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
View File
@@ -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
+77 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+2
View File
@@ -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 : */
+4
View File
@@ -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 : */