1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-12-25 14:52:19 +03:00

Try to correctly render marked text

This commit is contained in:
Tae Won Ha 2016-07-01 21:24:42 +02:00
parent 1d1c46c3fc
commit e685ef3581
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
10 changed files with 349 additions and 325 deletions

View File

@ -17,6 +17,6 @@
- (void)vimInput:(NSString * _Nonnull)input;
- (void)vimInputMarkedText:(NSString *_Nonnull)markedText;
- (void)debugScreenLines;
- (void)debug1;
@end

View File

@ -18,6 +18,4 @@
- (void)vimInput:(NSString *_Nonnull)input;
- (void)vimInputMarkedText:(NSString *_Nonnull)markedText;
- (void)debugScreenLines;
@end

View File

@ -18,6 +18,7 @@
#import <nvim/event/signal.h>
#import <nvim/main.h>
#define pun_type(t, x) (*((t *)(&x)))
typedef struct {
@ -48,9 +49,12 @@ static uv_cond_t _condition;
static id <NeoVimUiBridgeProtocol> _neo_vim_osx_ui;
static int _markedRow = 0;
static int _markedColumn = 0;
static NSString *_markedText = nil;
static int _marked_row = 0;
static int _marked_column = 0;
static int _put_row = -1;
static int _put_column = -1;
static NSString *_marked_text = nil;
static NSString *_backspace = nil;
static dispatch_queue_t _queue;
@ -129,234 +133,219 @@ static void suspend_event(void **argv) {
static void xpc_ui_resize(UI *ui __unused, int width, int height) {
xpc_async(^{
//printf("resize: %d:%d\n", width, height);
[_neo_vim_osx_ui resizeToWidth:width height:height];
[_neo_vim_osx_ui resizeToWidth:width height:height];
});
}
static void xpc_ui_clear(UI *ui __unused) {
xpc_async(^{
//printf("clear\n");
[_neo_vim_osx_ui clear];
[_neo_vim_osx_ui clear];
});
}
static void xpc_ui_eol_clear(UI *ui __unused) {
xpc_async(^{
//printf("eol clear\n");
[_neo_vim_osx_ui eolClear];
[_neo_vim_osx_ui eolClear];
});
}
static void xpc_ui_cursor_goto(UI *ui __unused, int row, int col) {
xpc_async(^{
//printf("cursor goto %d:%d\n", row, col);
[_neo_vim_osx_ui cursorGotoRow:row column:col];
_put_row = row;
_put_column = col;
[_neo_vim_osx_ui gotoPosition:(Position) { .row = row, .column = col }
screenCursor:(Position) { .row = cursorRow(), .column = cursorColumn() }
bufferCursor:(Position) { .row = curwin->w_cursor.lnum - 1, .column = curwin->w_cursor.col }];
});
}
static void xpc_ui_update_menu(UI *ui __unused) {
xpc_async(^{
//printf("update menu\n");
[_neo_vim_osx_ui updateMenu];
[_neo_vim_osx_ui updateMenu];
});
}
static void xpc_ui_busy_start(UI *ui __unused) {
xpc_async(^{
//printf("busy start\n");
[_neo_vim_osx_ui busyStart];
[_neo_vim_osx_ui busyStart];
});
}
static void xpc_ui_busy_stop(UI *ui __unused) {
xpc_async(^{
//printf("busy stop\n");
[_neo_vim_osx_ui busyStop];
[_neo_vim_osx_ui busyStop];
});
}
static void xpc_ui_mouse_on(UI *ui __unused) {
xpc_async(^{
//printf("mouse on\n");
[_neo_vim_osx_ui mouseOn];
[_neo_vim_osx_ui mouseOn];
});
}
static void xpc_ui_mouse_off(UI *ui __unused) {
xpc_async(^{
//printf("mouse off\n");
[_neo_vim_osx_ui mouseOff];
[_neo_vim_osx_ui mouseOff];
});
}
static void xpc_ui_mode_change(UI *ui __unused, int mode) {
xpc_async(^{
//printf("mode change %04x\n", mode);
[_neo_vim_osx_ui modeChange:mode];
[_neo_vim_osx_ui modeChange:mode];
});
}
static void xpc_ui_set_scroll_region(UI *ui __unused, int top, int bot, int left, int right) {
xpc_async(^{
//printf("set scroll region: %d, %d, %d, %d\n", top, bot, left, right);
[_neo_vim_osx_ui setScrollRegionToTop:top bottom:bot left:left right:right];
[_neo_vim_osx_ui setScrollRegionToTop:top bottom:bot left:left right:right];
});
}
static void xpc_ui_scroll(UI *ui __unused, int count) {
xpc_async(^{
//printf("scroll %d\n", count);
[_neo_vim_osx_ui scroll:count];
[_neo_vim_osx_ui scroll:count];
});
}
static void xpc_ui_highlight_set(UI *ui __unused, HlAttrs attrs) {
xpc_async(^{
//printf("highlight set\n");
FontTrait trait = FontTraitNone;
if (attrs.italic) {
trait |= FontTraitItalic;
}
if (attrs.bold) {
trait |= FontTraitBold;
}
if (attrs.underline) {
trait |= FontTraitUnderline;
}
if (attrs.undercurl) {
trait |= FontTraitUndercurl;
}
CellAttributes cellAttrs;
cellAttrs.fontTrait = trait;
FontTrait trait = FontTraitNone;
if (attrs.italic) {
trait |= FontTraitItalic;
}
if (attrs.bold) {
trait |= FontTraitBold;
}
if (attrs.underline) {
trait |= FontTraitUnderline;
}
if (attrs.undercurl) {
trait |= FontTraitUndercurl;
}
CellAttributes cellAttrs;
cellAttrs.fontTrait = trait;
unsigned int fg = attrs.foreground == -1 ? _default_foreground : pun_type(unsigned int, attrs.foreground);
unsigned int bg = attrs.background == -1 ? _default_background : pun_type(unsigned int, attrs.background);
unsigned int fg = attrs.foreground == -1 ? _default_foreground : pun_type(unsigned int, attrs.foreground);
unsigned int bg = attrs.background == -1 ? _default_background : pun_type(unsigned int, attrs.background);
cellAttrs.foreground = attrs.reverse ? bg : fg;
cellAttrs.background = attrs.reverse ? fg : bg;
cellAttrs.special = attrs.special == -1 ? _default_special : pun_type(unsigned int, attrs.special);
cellAttrs.foreground = attrs.reverse ? bg : fg;
cellAttrs.background = attrs.reverse ? fg : bg;
cellAttrs.special = attrs.special == -1 ? _default_special : pun_type(unsigned int, attrs.special);
[_neo_vim_osx_ui highlightSet:cellAttrs];
[_neo_vim_osx_ui highlightSet:cellAttrs];
});
}
static void xpc_ui_put(UI *ui __unused, uint8_t *str, size_t len) {
xpc_async(^{
NSString *string = [[NSString alloc] initWithBytes:str length:len encoding:NSUTF8StringEncoding];
// printf("put: %lu:'%s'\n", len, [string cStringUsingEncoding:NSUTF8StringEncoding]);
NSString *string = [[NSString alloc] initWithBytes:str length:len encoding:NSUTF8StringEncoding];
if (_markedText != nil && _markedColumn == cursorColumn() && _markedRow == cursorRow()) {
[_neo_vim_osx_ui putMarkedText:string];
} else if (_markedText != nil && len == 0 && _markedColumn == cursorColumn() - 1) {
[_neo_vim_osx_ui putMarkedText:string];
} else {
[_neo_vim_osx_ui put:string];
}
if (_marked_text != nil && _marked_row == _put_row && _marked_column == _put_column) {
// NSLog(@"!!! putting marked text: '%@'", string);
[_neo_vim_osx_ui putMarkedText:string];
} else if (_marked_text != nil && len == 0 && _marked_row == _put_row && _marked_column == _put_column - 1) {
// NSLog(@"!!! putting marked text cuz zero");
[_neo_vim_osx_ui putMarkedText:string];
} else {
// NSLog(@"putting non-marked text: '%@'", string);
[_neo_vim_osx_ui put:string];
}
[string release];
_put_column += 1;
[string release];
});
}
static void xpc_ui_bell(UI *ui __unused) {
xpc_async(^{
//printf("bell\n");
[_neo_vim_osx_ui bell];
[_neo_vim_osx_ui bell];
});
}
static void xpc_ui_visual_bell(UI *ui __unused) {
xpc_async(^{
//printf("visual bell\n");
[_neo_vim_osx_ui visualBell];
[_neo_vim_osx_ui visualBell];
});
}
static void xpc_ui_flush(UI *ui __unused) {
xpc_async(^{
//printf("flush\n");
[_neo_vim_osx_ui flush];
[_neo_vim_osx_ui flush];
});
}
static void xpc_ui_update_fg(UI *ui __unused, int fg) {
xpc_async(^{
// printf("update fg: %x\n", fg);
if (fg == -1) {
[_neo_vim_osx_ui updateForeground:_default_foreground];
return;
}
if (fg == -1) {
[_neo_vim_osx_ui updateForeground:_default_foreground];
return;
}
_default_foreground = pun_type(unsigned int, fg);
[_neo_vim_osx_ui updateForeground:fg];
_default_foreground = pun_type(unsigned int, fg);
[_neo_vim_osx_ui updateForeground:fg];
});
}
static void xpc_ui_update_bg(UI *ui __unused, int bg) {
xpc_async(^{
// printf("update bg: %x\n", bg);
if (bg == -1) {
[_neo_vim_osx_ui updateBackground:_default_background];
return;
}
if (bg == -1) {
[_neo_vim_osx_ui updateBackground:_default_background];
return;
}
_default_background = pun_type(unsigned int, bg);
[_neo_vim_osx_ui updateBackground:bg];
_default_background = pun_type(unsigned int, bg);
[_neo_vim_osx_ui updateBackground:bg];
});
}
static void xpc_ui_update_sp(UI *ui __unused, int sp) {
xpc_async(^{
// printf("update sp: %x\n", sp);
if (sp == -1) {
[_neo_vim_osx_ui updateSpecial:_default_special];
return;
}
if (sp == -1) {
[_neo_vim_osx_ui updateSpecial:_default_special];
return;
}
_default_special = pun_type(unsigned int, sp);
[_neo_vim_osx_ui updateSpecial:sp];
_default_special = pun_type(unsigned int, sp);
[_neo_vim_osx_ui updateSpecial:sp];
});
}
static void xpc_ui_suspend(UI *ui __unused) {
xpc_async(^{
//printf("suspend\n");
[_neo_vim_osx_ui suspend];
[_neo_vim_osx_ui suspend];
XpcUiData *data = ui->data;
// FIXME: dunno whether we need this: copied from tui.c
// kill(0, SIGTSTP) won't stop the UI thread, so we must poll for SIGCONT
// before continuing. This is done in another callback to avoid
// loop_poll_events recursion
queue_put_event(data->loop->fast_events, event_create(1, suspend_event, 1, ui));
XpcUiData *data = ui->data;
// FIXME: dunno whether we need this: copied from tui.c
// kill(0, SIGTSTP) won't stop the UI thread, so we must poll for SIGCONT
// before continuing. This is done in another callback to avoid
// loop_poll_events recursion
queue_put_event(data->loop->fast_events, event_create(1, suspend_event, 1, ui));
});
}
static void xpc_ui_set_title(UI *ui __unused, char *title) {
xpc_async(^{
//printf("set title: %s\n", title);
NSString *string = [[NSString alloc] initWithCString:title encoding:NSUTF8StringEncoding];
[_neo_vim_osx_ui setTitle:string];
[string release];
NSString *string = [[NSString alloc] initWithCString:title encoding:NSUTF8StringEncoding];
[_neo_vim_osx_ui setTitle:string];
[string release];
});
}
static void xpc_ui_set_icon(UI *ui __unused, char *icon) {
xpc_async(^{
//printf("set title: %s\n", icon);
NSString *string = [[NSString alloc] initWithCString:icon encoding:NSUTF8StringEncoding];
[_neo_vim_osx_ui setIcon:string];
[string release];
NSString *string = [[NSString alloc] initWithCString:icon encoding:NSUTF8StringEncoding];
[_neo_vim_osx_ui setIcon:string];
[string release];
});
}
static void xpc_ui_stop(UI *ui __unused) {
xpc_async(^{
//printf("stop\n");
[_neo_vim_osx_ui stop];
[_neo_vim_osx_ui stop];
XpcUiData *data = (XpcUiData *) ui->data;
data->stop = true;
XpcUiData *data = (XpcUiData *) ui->data;
data->stop = true;
});
}
@ -442,14 +431,18 @@ static void neovim_input(void **argv) {
uv_cond_destroy(&_condition);
uv_mutex_destroy(&_mutex);
// casting because [ui retain] returns an NSObject
_neo_vim_osx_ui = (id <NeoVimUiBridgeProtocol>) [ui retain];
[ui retain];
_neo_vim_osx_ui = ui;
_backspace = [[NSString alloc] initWithString:@"<BS>"];
return self;
}
- (void)dealloc {
[_neo_vim_osx_ui release];
[_backspace release];
// FIXME: uv_thread_join(&thread) here after terminating neovim
[super dealloc];
@ -460,64 +453,64 @@ static void neovim_input(void **argv) {
}
- (void)vimInput:(NSString *_Nonnull)input {
xpc_async(^{
if (_markedText == nil) {
loop_schedule(&main_loop, event_create(1, neovim_input, 1, [input retain])); // release in neovim_input
return;
}
// Handle cases like -> arrow key: The previously marked text is the same as the finalized text which should
// inserted. Neovim's drawing code is optimized such that it does not call put in this case again, thus, we
// have to manually unmark the cells in the main app.
if ([_markedText isEqualToString:input]) {
[_neo_vim_osx_ui unmarkRow:cursorRow() column:MAX(cursorColumn() - 1, 0)];
if (ScreenLines[cursorRow() * screen_Columns + MAX(cursorColumn() - 1, 0)] == 0x00) {
[_neo_vim_osx_ui unmarkRow:cursorRow() column:MAX(cursorColumn() - 2, 0)];
}
}
[self deleteMarkedText];
if (_marked_text == nil) {
loop_schedule(&main_loop, event_create(1, neovim_input, 1, [input retain])); // release in neovim_input
return;
}
// Handle cases like -> arrow key: The previously marked text is the same as the finalized text which should
// inserted. Neovim's drawing code is optimized such that it does not call put in this case again, thus, we have
// to manually unmark the cells in the main app.
if ([_marked_text isEqualToString:input]) {
// NSLog(@"unmarking text: '%@'\t now at %d:%d", input, _put_row, _put_column);
const char *str = [_marked_text cStringUsingEncoding:NSUTF8StringEncoding];
size_t cellCount = mb_string2cells((const char_u *) str);
for (int i = 1; i <= cellCount; i++) {
// NSLog(@"unmarking at %d:%d", _put_row, _put_column - i);
[_neo_vim_osx_ui unmarkRow:_put_row column:MAX(_put_column - i, 0)];
}
}
[self deleteMarkedText];
loop_schedule(&main_loop, event_create(1, neovim_input, 1, [input retain])); // release in neovim_input
});
}
- (void)vimInputMarkedText:(NSString *_Nonnull)markedText {
xpc_async(^{
if (_markedText != nil) {
[self deleteMarkedText];
}
if (_marked_text == nil) {
_marked_row = _put_row;
_marked_column = _put_column;
} else {
[self deleteMarkedText];
}
[self insertMarkedText:markedText];
// NSLog(@"inserting marked text '%@' at %d:%d", markedText, _put_row, _put_column);
[self insertMarkedText:markedText];
});
}
- (void)insertMarkedText:(NSString *_Nonnull)markedText {
_markedRow = cursorRow();
_markedColumn = cursorColumn();
_markedText = [markedText retain]; // release when the final text is input in -vimInput
_marked_text = [markedText retain]; // release when the final text is input in -vimInput
loop_schedule(&main_loop, event_create(1, neovim_input, 1, [_markedText retain])); // release in neovim_input
loop_schedule(&main_loop, event_create(1, neovim_input, 1, [_marked_text retain])); // release in neovim_input
}
- (void)deleteMarkedText {
NSUInteger length = [_markedText lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4;
NSUInteger length = [_marked_text lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4;
[_markedText release];
_markedText = nil;
[_marked_text release];
_marked_text = nil;
NSString *backspace = [[NSString alloc] initWithString:@"<BS>"];
for (int i = 0; i < length; i++) {
loop_schedule(&main_loop, event_create(1, neovim_input, 1, [backspace retain])); // release in neovim_input
loop_schedule(&main_loop, event_create(1, neovim_input, 1, [_backspace retain])); // release in neovim_input
}
[backspace release];
}
- (void)debugScreenLines {
NSLog(@"--- ScreenLines ---");
for (int i = 0; i < 20; i++) {
printf("%c,\n", ScreenLines[i]);
}
- (void)debug1 {
NSLog(@"_marked position: %d:%d", _marked_row, _marked_column);
NSLog(@"current cursor position: %d:%d", ui_current_row(), ui_current_col());
}
@end

View File

@ -26,15 +26,12 @@ struct Cell: CustomStringConvertible {
}
}
struct Position: CustomStringConvertible {
extension Position: CustomStringConvertible {
static let zero = Position(row: 0, column: 0)
static let null = Position(row: -1, column: -1)
var row: Int
var column: Int
var description: String {
public var description: String {
return "Position<\(self.row):\(self.column)>"
}
}
@ -78,7 +75,8 @@ class Grid: CustomStringConvertible {
private(set) var region = Region.zero
private(set) var size = Size.zero
private(set) var position = Position.zero
private(set) var putPosition = Position.zero
private(set) var screenCursor = Position.zero
var foreground = qDefaultForeground
var background = qDefaultBackground
@ -102,7 +100,7 @@ class Grid: CustomStringConvertible {
func resize(size: Size) {
self.region = Region(top: 0, bottom: size.height - 1, left: 0, right: size.width - 1)
self.size = size
self.position = Position.zero
self.putPosition = Position.zero
let emptyCellAttrs = CellAttributes(fontTrait: .None,
foreground: self.foreground, background: self.background, special: self.special)
@ -117,7 +115,7 @@ class Grid: CustomStringConvertible {
func eolClear() {
self.clearRegion(
Region(top: self.position.row, bottom: self.position.row, left: self.position.column, right: self.region.right)
Region(top: self.putPosition.row, bottom: self.putPosition.row, left: self.putPosition.column, right: self.region.right)
)
}
@ -156,7 +154,11 @@ class Grid: CustomStringConvertible {
}
func goto(position: Position) {
self.position = position
self.putPosition = position
}
func moveCursor(position: Position) {
self.screenCursor = position
}
func put(string: String) {
@ -165,14 +167,17 @@ class Grid: CustomStringConvertible {
// =>
// |abcde>| <- ">" at the end of the line is wrong -> the XPC could tell the main app whether the string occupies
// | | two cells using vim_strwidth()
self.cells[self.position.row][self.position.column] = Cell(string: string, attrs: self.attrs)
self.position.column += 1
self.cells[self.putPosition.row][self.putPosition.column] = Cell(string: string, attrs: self.attrs)
// Increment the column of the put position because neovim calls sets the position only once when drawing
// consecutive cells in the same line
self.putPosition.column += 1
}
func putMarkedText(string: String) {
// NOTE: Maybe there's a better way to indicate marked text than inverting...
self.cells[self.position.row][self.position.column] = Cell(string: string, attrs: self.attrs, marked: true)
self.position.column += 1
self.cells[self.putPosition.row][self.putPosition.column] = Cell(string: string, attrs: self.attrs, marked: true)
self.putPosition.column += 1
}
func unmarkCell(position: Position) {
@ -200,13 +205,17 @@ class Grid: CustomStringConvertible {
}
func isPreviousCellEmpty(position: Position) -> Bool {
return self.isCellEmpty(Position(row: position.row, column: max(position.column - 1, 0)))
return self.isCellEmpty(self.previousCellPosition(position))
}
func isNextCellEmpty(position: Position) -> Bool {
return self.isCellEmpty(Position(row: position.row, column: min(position.column + 1, self.size.width - 1)))
return self.isCellEmpty(self.nextCellPosition(position))
}
func previousCellPosition(position: Position) -> Position {
return Position(row: position.row, column: max(position.column - 1, 0))
}
func nextCellPosition(position: Position) -> Position {
return Position(row: position.row, column: min(position.column + 1, self.size.width - 1))
}

View File

@ -21,6 +21,11 @@ typedef struct {
unsigned int special;
} CellAttributes;
typedef struct {
NSInteger row;
NSInteger column;
} Position;
#define qDefaultForeground 0xFF000000
#define qDefaultBackground 0xFFFFFFFF
#define qDefaultSpecial 0xFFFF0000
@ -49,7 +54,7 @@ typedef struct {
* 2. NeoVim wants to put the cursor at (row, column).
* In case of 1. NeoVim will put in subsequent call. In case of 2. NeoVim seems to flush twice in a row.
*/
- (void)cursorGotoRow:(int)row column:(int)column;
- (void)gotoPosition:(Position)position screenCursor:(Position)screenCursor bufferCursor:(Position)bufferCursor;
- (void)updateMenu;
- (void)busyStart;

View File

@ -118,14 +118,15 @@ public class NeoVimView: NSView {
self.rowRunIntersecting(rects: dirtyRects).forEach { rowFrag in
// For background drawing we don't filter out the put(0, 0)s: in some cases only the put(0, 0)-cells should be
// redrawn.
self.drawBackground(positions: rowFrag.range.map { self.positionOnView(rowFrag.row, column: $0) },
// redrawn. => FIXME: probably we have to consider this also when drawing further down, ie when the range starts
// with '0'...
self.drawBackground(positions: rowFrag.range.map { self.pointInView(rowFrag.row, column: $0) },
background: rowFrag.attrs.background)
let positions = rowFrag.range
// filter out the put(0, 0)s (after a wide character)
.filter { self.grid.cells[rowFrag.row][$0].string.characters.count > 0 }
.map { self.positionOnView(rowFrag.row, column: $0) }
.map { self.pointInView(rowFrag.row, column: $0) }
if positions.isEmpty {
return
@ -144,7 +145,7 @@ public class NeoVimView: NSView {
private func drawCursor(background: UInt32) {
// FIXME: for now do some rudimentary cursor drawing
let cursorPosition = self.grid.position
let cursorPosition = self.grid.screenCursor
// Swift.print("\(#function): \(cursorPosition)")
var cursorRect = self.cellRect(row: cursorPosition.row, column: cursorPosition.column)
@ -153,7 +154,8 @@ public class NeoVimView: NSView {
cursorRect = cursorRect.union(self.cellRect(row: nextPosition.row, column:nextPosition.column))
}
ColorUtils.colorFromCodeIgnoringAlpha(background).set()
// set cursor to an abhorrent color for debugging
ColorUtils.colorFromCodeIgnoringAlpha(0xFF990000).set()
NSRectFillUsingOperation(cursorRect, .CompositeDifference)
}
@ -203,16 +205,24 @@ public class NeoVimView: NSView {
} // All RowRuns for all Regions grouped by Region.
.flatMap { $0 } // Flattened RowRuns for all Regions.
}
func pointInView(position: Position) -> CGPoint {
return self.pointInView(position.row, column: position.column)
}
func positionOnView(row: Int, column: Int) -> CGPoint {
func pointInView(row: Int, column: Int) -> CGPoint {
return CGPoint(
x: CGFloat(column) * self.cellSize.width,
y: self.frame.size.height - CGFloat(row) * self.cellSize.height - self.cellSize.height
)
}
func cellRect(position: Position) -> CGRect {
return self.cellRect(row: position.row, column: position.column)
}
func cellRect(row row: Int, column: Int) -> CGRect {
return CGRect(origin: self.positionOnView(row, column: column), size: self.cellSize)
return CGRect(origin: self.pointInView(row, column: column), size: self.cellSize)
}
func regionRect(region: Region) -> CGRect {

View File

@ -34,7 +34,7 @@ extension NeoVimView: NSTextInputClient {
}
public func insertText(aString: AnyObject, replacementRange: NSRange) {
NSLog("\(#function): \(replacementRange): \(aString)")
NSLog("\(#function): \(replacementRange): '\(aString)'")
switch aString {
case let string as String:
@ -49,14 +49,14 @@ extension NeoVimView: NSTextInputClient {
self.markedText = nil
self.markedPosition = Position.null
// TODO: necessary?
self.setNeedsDisplayInRect(self.cellRect(row: self.grid.position.row, column: self.grid.position.column))
self.setNeedsDisplayInRect(self.cellRect(row: self.grid.putPosition.row, column: self.grid.putPosition.column))
self.keyDownDone = true
}
public override func doCommandBySelector(aSelector: Selector) {
// NSLog("\(#function): "\(aSelector)")
// TODO: handle when -> delete
// FIXME: handle when -> delete
if self.respondsToSelector(aSelector) {
Swift.print("\(#function): calling \(aSelector)")
@ -72,7 +72,7 @@ extension NeoVimView: NSTextInputClient {
public func setMarkedText(aString: AnyObject, selectedRange: NSRange, replacementRange: NSRange) {
if self.markedText == nil {
self.markedPosition = self.grid.position
self.markedPosition = self.grid.putPosition
}
switch aString {
@ -95,7 +95,7 @@ extension NeoVimView: NSTextInputClient {
self.markedText = nil
self.markedPosition = Position.null
// TODO: necessary?
self.setNeedsDisplayInRect(self.cellRect(row: self.grid.position.row, column: self.grid.position.column))
self.setNeedsDisplayInRect(self.cellRect(row: self.grid.putPosition.row, column: self.grid.putPosition.column))
self.keyDownDone = true
}
@ -110,19 +110,19 @@ extension NeoVimView: NSTextInputClient {
// }
// FIXME: do we have to handle positions at the column borders?
if self.grid.isPreviousCellEmpty(self.grid.position) {
if self.grid.isPreviousCellEmpty(self.grid.putPosition) {
let result = NSRange(
location: self.grid.singleIndexFrom(
Position(row: self.grid.position.row, column: self.grid.position.column - 1)
Position(row: self.grid.putPosition.row, column: self.grid.putPosition.column - 1)
),
length: 0
)
NSLog("\(#function): \(result)")
// NSLog("\(#function): \(result)")
return result
}
let result = NSRange(location: self.grid.singleIndexFrom(self.grid.position), length: 0)
NSLog("\(#function): \(result)")
let result = NSRange(location: self.grid.singleIndexFrom(self.grid.putPosition), length: 0)
// NSLog("\(#function): \(result)")
return result
}
@ -131,11 +131,11 @@ extension NeoVimView: NSTextInputClient {
if let markedText = self.markedText {
let result = NSRange(location: self.grid.singleIndexFrom(self.markedPosition),
length: markedText.characters.count)
NSLog("\(#function): \(result)")
// NSLog("\(#function): \(result)")
return result
}
NSLog("\(#function): returning empty range")
// NSLog("\(#function): returning empty range")
return NSRange(location: NSNotFound, length: 0)
}
@ -168,36 +168,29 @@ extension NeoVimView: NSTextInputClient {
$0 + $1.string
}
actualRange[0].length = string.characters.count
NSLog("\(#function): \(aRange), \(actualRange[0]): \(string)")
// NSLog("\(#function): \(aRange), \(actualRange[0]): \(string)")
return NSAttributedString(string: string)
}
// TODO: maybe make Grid a Indexable or similar
// FIXME: maybe make Grid a Indexable or similar
var string = ""
for i in location...(location + length) {
string += self.grid.cellForSingleIndex(i).string
}
NSLog("\(#function): \(aRange), \(actualRange[0]): \(string)")
// NSLog("\(#function): \(aRange), \(actualRange[0]): \(string)")
return NSAttributedString(string: string)
}
public func validAttributesForMarkedText() -> [String] {
// Swift.print("\(#function): ")
return []
}
public func firstRectForCharacterRange(aRange: NSRange, actualRange: NSRangePointer) -> NSRect {
NSLog("\(#function): \(aRange), \(actualRange[0])")
if actualRange != nil {
Swift.print("\(#function): \(aRange), \(actualRange[0])")
} else {
Swift.print("\(#function): \(aRange), nil")
}
let position = self.grid.positionFromSingleIndex(aRange.location)
NSLog("\(#function): \(aRange),\(actualRange[0]) -> \(position.row):\(position.column)")
let row = Int(floor(Double(aRange.location / self.grid.size.width)))
let column = aRange.location - row * self.grid.size.width
let resultInSelf = self.cellRect(row: row, column: column)
let resultInSelf = self.cellRect(row: position.row, column: position.column)
let result = self.window?.convertRectToScreen(self.convertRect(resultInSelf, toView: nil))
return result!
@ -229,95 +222,95 @@ extension NeoVimView: NSTextInputClient {
return result
}
/*
public func moveWordForward(sender: AnyObject?)
public func moveWordBackward(sender: AnyObject?)
public func moveToBeginningOfLine(sender: AnyObject?)
public func moveToEndOfLine(sender: AnyObject?)
public func moveToBeginningOfParagraph(sender: AnyObject?)
public func moveToEndOfParagraph(sender: AnyObject?)
public func moveToEndOfDocument(sender: AnyObject?)
public func moveToBeginningOfDocument(sender: AnyObject?)
public func pageDown(sender: AnyObject?)
public func pageUp(sender: AnyObject?)
public func centerSelectionInVisibleArea(sender: AnyObject?)
public func moveBackwardAndModifySelection(sender: AnyObject?)
public func moveForwardAndModifySelection(sender: AnyObject?)
public func moveWordForwardAndModifySelection(sender: AnyObject?)
public func moveWordBackwardAndModifySelection(sender: AnyObject?)
public func moveUpAndModifySelection(sender: AnyObject?)
public func moveDownAndModifySelection(sender: AnyObject?)
public func moveToBeginningOfLineAndModifySelection(sender: AnyObject?)
public func moveToEndOfLineAndModifySelection(sender: AnyObject?)
public func moveToBeginningOfParagraphAndModifySelection(sender: AnyObject?)
public func moveToEndOfParagraphAndModifySelection(sender: AnyObject?)
public func moveToEndOfDocumentAndModifySelection(sender: AnyObject?)
public func moveToBeginningOfDocumentAndModifySelection(sender: AnyObject?)
public func pageDownAndModifySelection(sender: AnyObject?)
public func pageUpAndModifySelection(sender: AnyObject?)
public func moveParagraphForwardAndModifySelection(sender: AnyObject?)
public func moveParagraphBackwardAndModifySelection(sender: AnyObject?)
public func moveWordRight(sender: AnyObject?)
public func moveWordLeft(sender: AnyObject?)
public func moveRightAndModifySelection(sender: AnyObject?)
public func moveLeftAndModifySelection(sender: AnyObject?)
public func moveWordRightAndModifySelection(sender: AnyObject?)
public func moveWordLeftAndModifySelection(sender: AnyObject?)
public func moveToLeftEndOfLine(sender: AnyObject?)
public func moveToRightEndOfLine(sender: AnyObject?)
public func moveToLeftEndOfLineAndModifySelection(sender: AnyObject?)
public func moveToRightEndOfLineAndModifySelection(sender: AnyObject?)
public func scrollLineUp(sender: AnyObject?)
public func scrollLineDown(sender: AnyObject?)
public func transpose(sender: AnyObject?)
public func transposeWords(sender: AnyObject?)
public func selectAll(sender: AnyObject?)
public func selectParagraph(sender: AnyObject?)
public func selectLine(sender: AnyObject?)
public func selectWord(sender: AnyObject?)
public func indent(sender: AnyObject?)
public func insertTab(sender: AnyObject?)
public func insertBacktab(sender: AnyObject?)
public func insertNewline(sender: AnyObject?)
public func insertParagraphSeparator(sender: AnyObject?)
public func insertNewlineIgnoringFieldEditor(sender: AnyObject?)
public func insertTabIgnoringFieldEditor(sender: AnyObject?)
public func insertLineBreak(sender: AnyObject?)
public func insertContainerBreak(sender: AnyObject?)
public func insertSingleQuoteIgnoringSubstitution(sender: AnyObject?)
public func insertDoubleQuoteIgnoringSubstitution(sender: AnyObject?)
public func changeCaseOfLetter(sender: AnyObject?)
public func uppercaseWord(sender: AnyObject?)
public func lowercaseWord(sender: AnyObject?)
public func capitalizeWord(sender: AnyObject?)
public func deleteBackwardByDecomposingPreviousCharacter(sender: AnyObject?)
public func deleteWordForward(sender: AnyObject?)
public func deleteWordBackward(sender: AnyObject?)
public func deleteToBeginningOfLine(sender: AnyObject?)
public func deleteToEndOfLine(sender: AnyObject?)
public func deleteToBeginningOfParagraph(sender: AnyObject?)
public func deleteToEndOfParagraph(sender: AnyObject?)
public func yank(sender: AnyObject?)
public func complete(sender: AnyObject?)
public func setMark(sender: AnyObject?)
public func deleteToMark(sender: AnyObject?)
public func selectToMark(sender: AnyObject?)
public func swapWithMark(sender: AnyObject?)
public func cancelOperation(sender: AnyObject?)
*/
}
/*
public func moveWordForward(sender: AnyObject?)
public func moveWordBackward(sender: AnyObject?)
public func moveToBeginningOfLine(sender: AnyObject?)
public func moveToEndOfLine(sender: AnyObject?)
public func moveToBeginningOfParagraph(sender: AnyObject?)
public func moveToEndOfParagraph(sender: AnyObject?)
public func moveToEndOfDocument(sender: AnyObject?)
public func moveToBeginningOfDocument(sender: AnyObject?)
public func pageDown(sender: AnyObject?)
public func pageUp(sender: AnyObject?)
public func centerSelectionInVisibleArea(sender: AnyObject?)
public func moveBackwardAndModifySelection(sender: AnyObject?)
public func moveForwardAndModifySelection(sender: AnyObject?)
public func moveWordForwardAndModifySelection(sender: AnyObject?)
public func moveWordBackwardAndModifySelection(sender: AnyObject?)
public func moveUpAndModifySelection(sender: AnyObject?)
public func moveDownAndModifySelection(sender: AnyObject?)
public func moveToBeginningOfLineAndModifySelection(sender: AnyObject?)
public func moveToEndOfLineAndModifySelection(sender: AnyObject?)
public func moveToBeginningOfParagraphAndModifySelection(sender: AnyObject?)
public func moveToEndOfParagraphAndModifySelection(sender: AnyObject?)
public func moveToEndOfDocumentAndModifySelection(sender: AnyObject?)
public func moveToBeginningOfDocumentAndModifySelection(sender: AnyObject?)
public func pageDownAndModifySelection(sender: AnyObject?)
public func pageUpAndModifySelection(sender: AnyObject?)
public func moveParagraphForwardAndModifySelection(sender: AnyObject?)
public func moveParagraphBackwardAndModifySelection(sender: AnyObject?)
public func moveWordRight(sender: AnyObject?)
public func moveWordLeft(sender: AnyObject?)
public func moveRightAndModifySelection(sender: AnyObject?)
public func moveLeftAndModifySelection(sender: AnyObject?)
public func moveWordRightAndModifySelection(sender: AnyObject?)
public func moveWordLeftAndModifySelection(sender: AnyObject?)
public func moveToLeftEndOfLine(sender: AnyObject?)
public func moveToRightEndOfLine(sender: AnyObject?)
public func moveToLeftEndOfLineAndModifySelection(sender: AnyObject?)
public func moveToRightEndOfLineAndModifySelection(sender: AnyObject?)
public func scrollLineUp(sender: AnyObject?)
public func scrollLineDown(sender: AnyObject?)
public func transpose(sender: AnyObject?)
public func transposeWords(sender: AnyObject?)
public func selectAll(sender: AnyObject?)
public func selectParagraph(sender: AnyObject?)
public func selectLine(sender: AnyObject?)
public func selectWord(sender: AnyObject?)
public func indent(sender: AnyObject?)
public func insertTab(sender: AnyObject?)
public func insertBacktab(sender: AnyObject?)
public func insertNewline(sender: AnyObject?)
public func insertParagraphSeparator(sender: AnyObject?)
public func insertNewlineIgnoringFieldEditor(sender: AnyObject?)
public func insertTabIgnoringFieldEditor(sender: AnyObject?)
public func insertLineBreak(sender: AnyObject?)
public func insertContainerBreak(sender: AnyObject?)
public func insertSingleQuoteIgnoringSubstitution(sender: AnyObject?)
public func insertDoubleQuoteIgnoringSubstitution(sender: AnyObject?)
public func changeCaseOfLetter(sender: AnyObject?)
public func uppercaseWord(sender: AnyObject?)
public func lowercaseWord(sender: AnyObject?)
public func capitalizeWord(sender: AnyObject?)
public func deleteBackwardByDecomposingPreviousCharacter(sender: AnyObject?)
public func deleteWordForward(sender: AnyObject?)
public func deleteWordBackward(sender: AnyObject?)
public func deleteToBeginningOfLine(sender: AnyObject?)
public func deleteToEndOfLine(sender: AnyObject?)
public func deleteToBeginningOfParagraph(sender: AnyObject?)
public func deleteToEndOfParagraph(sender: AnyObject?)
public func yank(sender: AnyObject?)
public func complete(sender: AnyObject?)
public func setMark(sender: AnyObject?)
public func deleteToMark(sender: AnyObject?)
public func selectToMark(sender: AnyObject?)
public func swapWithMark(sender: AnyObject?)
public func cancelOperation(sender: AnyObject?)
*/

View File

@ -17,6 +17,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
// Swift.print("### resize to \(width):\(height)")
self.grid.resize(Size(width: Int(width), height: Int(height)))
self.delegate?.resizeToSize(rectSize)
// TODO: set needs display?
}
}
@ -33,9 +34,9 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
// Swift.print("### eol clear")
self.grid.eolClear()
let origin = self.positionOnView(self.grid.position.row, column: self.grid.position.column)
let origin = self.pointInView(self.grid.putPosition)
let size = CGSize(
width: CGFloat(self.grid.region.right - self.grid.position.column + 1) * self.cellSize.width,
width: CGFloat(self.grid.region.right - self.grid.putPosition.column + 1) * self.cellSize.width,
height: self.cellSize.height
)
let rect = CGRect(origin: origin, size: size)
@ -43,12 +44,15 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
}
}
public func cursorGotoRow(row: Int32, column: Int32) {
public func gotoPosition(position: Position, screenCursor: Position, bufferCursor: Position) {
DispatchUtils.gui {
NSLog("\(#function): \(row):\(column)")
self.setCursorNeedsDisplay(self.grid.position)
self.grid.goto(Position(row: Int(row), column: Int(column)))
self.setCursorNeedsDisplay(self.grid.position)
// NSLog("\(#function): \(position), \(screenCursor), \(bufferCursor)")
self.setNeedsDisplay(cellPosition: self.grid.screenCursor) // redraw where the cursor was till now
self.setNeedsDisplay(screenCursor: screenCursor) // draw the new cursor
self.grid.goto(position)
self.grid.moveCursor(screenCursor)
}
}
@ -81,7 +85,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
DispatchUtils.gui {
let region = Region(top: Int(top), bottom: Int(bottom), left: Int(left), right: Int(right))
self.grid.setScrollRegion(region)
self.setNeedsDisplayInRect(self.regionRect(region))
self.setNeedsDisplay(region: region)
}
}
@ -90,7 +94,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
DispatchUtils.gui {
self.grid.scroll(Int(count))
self.setNeedsDisplayInRect(self.regionRect(self.grid.region))
self.setNeedsDisplay(region: self.grid.region)
}
}
@ -103,30 +107,26 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
public func put(string: String) {
DispatchUtils.gui {
// Swift.print("\(#function): \(string)")
let curPos = Position(row: self.grid.position.row, column: self.grid.position.column)
// Swift.print("\(#function): \(curPos) -> \(string)")
let curPos = self.grid.putPosition
// NSLog("\(#function): \(curPos) -> \(string)")
self.grid.put(string)
self.setNeedsDisplayAt(position: curPos)
if string.characters.count == 0 {
self.setNeedsDisplayAt(row: curPos.row, column: max(curPos.column - 1, 0))
}
self.setCursorNeedsDisplay(self.grid.position)
self.setNeedsDisplay(cellPosition: curPos)
self.setNeedsDisplay(screenCursor: self.grid.screenCursor)
}
}
public func putMarkedText(markedText: String) {
DispatchUtils.gui {
// Swift.print("\(#function): \(markedText)")
let curPos = Position(row: self.grid.position.row, column: self.grid.position.column)
let curPos = self.grid.putPosition
self.grid.putMarkedText(markedText)
self.setNeedsDisplayAt(position: curPos)
self.setNeedsDisplay(position: curPos)
if markedText.characters.count == 0 {
self.setNeedsDisplayAt(row: curPos.row, column: max(curPos.column - 1, 0))
self.setNeedsDisplay(position: self.grid.previousCellPosition(curPos))
}
self.setCursorNeedsDisplay(self.grid.position)
self.setNeedsDisplay(screenCursor: self.grid.screenCursor)
}
}
@ -134,8 +134,8 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
DispatchUtils.gui {
// Swift.print("\(#function): \(row):\(column)")
self.grid.unmarkCell(Position(row: Int(row), column: Int(column)))
self.setNeedsDisplayAt(row: Int(row), column: Int(column))
self.setCursorNeedsDisplay(self.grid.position)
self.setNeedsDisplay(row: Int(row), column: Int(column))
self.setNeedsDisplay(screenCursor: self.grid.screenCursor)
}
}
@ -191,20 +191,36 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
public func stop() {
// Swift.print("### stop")
}
private func setNeedsDisplayAt(position position: Position) {
self.setNeedsDisplayAt(row: position.row, column: position.column)
private func setNeedsDisplay(region region: Region) {
self.setNeedsDisplayInRect(self.regionRect(region))
}
private func setNeedsDisplay(cellPosition position: Position) {
self.setNeedsDisplay(position: position)
if self.grid.isCellEmpty(position) {
self.setNeedsDisplay(position: self.grid.previousCellPosition(position))
}
if self.grid.isNextCellEmpty(position) {
self.setNeedsDisplay(position: self.grid.nextCellPosition(position))
}
}
private func setNeedsDisplayAt(row row: Int, column: Int) {
private func setNeedsDisplay(position position: Position) {
self.setNeedsDisplay(row: position.row, column: position.column)
}
private func setNeedsDisplay(row row: Int, column: Int) {
// Swift.print("\(#function): \(row):\(column)")
self.setNeedsDisplayInRect(self.cellRect(row: row, column: column))
}
private func setCursorNeedsDisplay(position: Position) {
self.setNeedsDisplayAt(position: position)
private func setNeedsDisplay(screenCursor position: Position) {
self.setNeedsDisplay(position: position)
if self.grid.isNextCellEmpty(position) {
self.setNeedsDisplayAt(position: self.grid.nextCellPosition(position))
self.setNeedsDisplay(position: self.grid.nextCellPosition(position))
}
}
}

View File

@ -13,7 +13,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NeoVimViewDelegate {
var neoVim: NeoVim!
@IBAction func debugSomething(sender: AnyObject!) {
self.neoVim.view.debugInfo()
self.neoVim.xpc.debug1()
}
func applicationDidFinishLaunching(aNotification: NSNotification) {

View File

@ -670,15 +670,15 @@
<window title="nvox" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="335" y="390" width="480" height="360"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1177"/>
<rect key="contentRect" x="335" y="390" width="363" height="251"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<view key="contentView" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
<rect key="frame" x="0.0" y="0.0" width="363" height="251"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZFX-rs-9SG">
<rect key="frame" x="14" y="312" width="81" height="32"/>
<buttonCell key="cell" type="push" title="Button" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="0RU-xD-r4y">
<rect key="frame" x="14" y="203" width="80" height="32"/>
<buttonCell key="cell" type="push" title="Debug" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="0RU-xD-r4y">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
@ -688,7 +688,7 @@
</button>
</subviews>
</view>
<point key="canvasLocation" x="179" y="272"/>
<point key="canvasLocation" x="274.5" y="441.5"/>
</window>
</objects>
</document>