1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-11-24 03:25:03 +03:00

Make hanja menu pop up

- Very rudimentary: since we don't use the replacement range when
  setting marked text, the original hangul character won't be replaced.
- We probably should use a different mechanism for returning attributed
  string: e.g. ask neovim to return the correct string...
This commit is contained in:
Tae Won Ha 2016-06-29 22:28:02 +02:00
parent 5a8fdbe9bc
commit 1d1c46c3fc
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
6 changed files with 259 additions and 267 deletions

View File

@ -48,14 +48,20 @@ static uv_cond_t _condition;
static id <NeoVimUiBridgeProtocol> _neo_vim_osx_ui; static id <NeoVimUiBridgeProtocol> _neo_vim_osx_ui;
static int _row = 0;
static int _column = 0;
static int _markedRow = 0; static int _markedRow = 0;
static int _markedColumn = 0; static int _markedColumn = 0;
static NSString *_markedText = nil; static NSString *_markedText = nil;
static dispatch_queue_t _queue; static dispatch_queue_t _queue;
static inline int cursorRow() {
return curwin->w_winrow + curwin->w_wrow;
}
static inline int cursorColumn() {
return curwin->w_wincol + curwin->w_wcol;
}
static void xpc_async(void (^block)()) { static void xpc_async(void (^block)()) {
dispatch_async(_queue, block); dispatch_async(_queue, block);
} }
@ -145,9 +151,6 @@ static void xpc_ui_eol_clear(UI *ui __unused) {
static void xpc_ui_cursor_goto(UI *ui __unused, int row, int col) { static void xpc_ui_cursor_goto(UI *ui __unused, int row, int col) {
xpc_async(^{ xpc_async(^{
//printf("cursor goto %d:%d\n", row, col); //printf("cursor goto %d:%d\n", row, col);
_row = row;
_column = col;
[_neo_vim_osx_ui cursorGotoRow:row column:col]; [_neo_vim_osx_ui cursorGotoRow:row column:col];
}); });
} }
@ -243,15 +246,14 @@ static void xpc_ui_put(UI *ui __unused, uint8_t *str, size_t len) {
NSString *string = [[NSString alloc] initWithBytes:str length:len encoding:NSUTF8StringEncoding]; NSString *string = [[NSString alloc] initWithBytes:str length:len encoding:NSUTF8StringEncoding];
// printf("put: %lu:'%s'\n", len, [string cStringUsingEncoding:NSUTF8StringEncoding]); // printf("put: %lu:'%s'\n", len, [string cStringUsingEncoding:NSUTF8StringEncoding]);
if (_markedText != nil && _markedColumn == _column && _markedRow == _row) { if (_markedText != nil && _markedColumn == cursorColumn() && _markedRow == cursorRow()) {
[_neo_vim_osx_ui putMarkedText:string]; [_neo_vim_osx_ui putMarkedText:string];
} else if (_markedText != nil && len == 0 && _markedColumn == _column - 1) { } else if (_markedText != nil && len == 0 && _markedColumn == cursorColumn() - 1) {
[_neo_vim_osx_ui putMarkedText:string]; [_neo_vim_osx_ui putMarkedText:string];
} else { } else {
[_neo_vim_osx_ui put:string]; [_neo_vim_osx_ui put:string];
} }
_column += 1;
[string release]; [string release];
}); });
} }
@ -458,6 +460,7 @@ static void neovim_input(void **argv) {
} }
- (void)vimInput:(NSString *_Nonnull)input { - (void)vimInput:(NSString *_Nonnull)input {
xpc_async(^{ xpc_async(^{
if (_markedText == nil) { if (_markedText == nil) {
loop_schedule(&main_loop, event_create(1, neovim_input, 1, [input retain])); // release in neovim_input loop_schedule(&main_loop, event_create(1, neovim_input, 1, [input retain])); // release in neovim_input
@ -468,9 +471,9 @@ static void neovim_input(void **argv) {
// inserted. Neovim's drawing code is optimized such that it does not call put in this case again, thus, we // 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. // have to manually unmark the cells in the main app.
if ([_markedText isEqualToString:input]) { if ([_markedText isEqualToString:input]) {
[_neo_vim_osx_ui unmarkRow:_row column:MAX(_column - 1, 0)]; [_neo_vim_osx_ui unmarkRow:cursorRow() column:MAX(cursorColumn() - 1, 0)];
if (ScreenLines[_row * screen_Columns + MAX(_column - 1, 0)] == 0x00) { if (ScreenLines[cursorRow() * screen_Columns + MAX(cursorColumn() - 1, 0)] == 0x00) {
[_neo_vim_osx_ui unmarkRow:_row column:MAX(_column - 2, 0)]; [_neo_vim_osx_ui unmarkRow:cursorRow() column:MAX(cursorColumn() - 2, 0)];
} }
} }
@ -490,8 +493,8 @@ static void neovim_input(void **argv) {
} }
- (void)insertMarkedText:(NSString *_Nonnull)markedText { - (void)insertMarkedText:(NSString *_Nonnull)markedText {
_markedRow = _row; _markedRow = cursorRow();
_markedColumn = _column; _markedColumn = cursorColumn();
_markedText = [markedText retain]; // release when the final text is input in -vimInput _markedText = [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, [_markedText retain])); // release in neovim_input

View File

@ -29,6 +29,7 @@ struct Cell: CustomStringConvertible {
struct Position: CustomStringConvertible { struct Position: CustomStringConvertible {
static let zero = Position(row: 0, column: 0) static let zero = Position(row: 0, column: 0)
static let null = Position(row: -1, column: -1)
var row: Int var row: Int
var column: Int var column: Int
@ -175,21 +176,45 @@ class Grid: CustomStringConvertible {
} }
func unmarkCell(position: Position) { func unmarkCell(position: Position) {
print("!!!!! unmarking: \(position)") // NSLog("\(#function): \(position)")
self.cells[position.row][position.column].marked = false self.cells[position.row][position.column].marked = false
} }
func isNextCellEmpty(position: Position) -> Bool { func singleIndexFrom(position: Position) -> Int {
if self.cells[position.row][min(position.column + 1, self.size.width - 1)].string.characters.count == 0 { return position.row * self.size.width + position.column
}
func positionFromSingleIndex(idx: Int) -> Position {
let row = Int(floor(Double(idx) / Double(self.size.width)))
let column = idx - row * self.size.width
return Position(row: row, column: column)
}
func isCellEmpty(position: Position) -> Bool {
if self.cells[position.row][position.column].string.characters.count == 0 {
return true return true
} }
return false return false
} }
func isPreviousCellEmpty(position: Position) -> Bool {
return self.isCellEmpty(Position(row: position.row, column: max(position.column - 1, 0)))
}
func isNextCellEmpty(position: Position) -> Bool {
return self.isCellEmpty(Position(row: position.row, column: min(position.column + 1, self.size.width - 1)))
}
func nextCellPosition(position: Position) -> Position { func nextCellPosition(position: Position) -> Position {
return Position(row: position.row, column: min(position.column + 1, self.size.width - 1)) return Position(row: position.row, column: min(position.column + 1, self.size.width - 1))
} }
func cellForSingleIndex(idx: Int) -> Cell {
let position = self.positionFromSingleIndex(idx)
return self.cells[position.row][position.column]
}
private func clearRegion(region: Region) { private func clearRegion(region: Region) {
// FIXME: sometimes clearRegion gets called without first resizing the Grid. Should we handle this? // FIXME: sometimes clearRegion gets called without first resizing the Grid. Should we handle this?

View File

@ -16,125 +16,17 @@ public class InputTestView: NSView, NSTextInputClient {
*/ */
public func insertText(aString: AnyObject, replacementRange: NSRange) { public func insertText(aString: AnyObject, replacementRange: NSRange) {
Swift.print("\(#function): \(aString), \(replacementRange)") Swift.print("\(#function): \(aString), \(replacementRange)")
self.vimInput(String(aString))
self.markedText = nil self.markedText = nil
} }
/* The receiver invokes the action specified by aSelector. /* The receiver invokes the action specified by aSelector.
*/ */
public override func doCommandBySelector(aSelector: Selector) { public override func doCommandBySelector(aSelector: Selector) {
self.handledBySelector = true
Swift.print("\(#function): \(aSelector)") Swift.print("\(#function): \(aSelector)")
if aSelector == NSSelectorFromString("noop:") { if aSelector == NSSelectorFromString("noop:") {
self.handledBySelector = false self.handledBySelector = false
return return
} }
/*
public func moveForward(sender: AnyObject?)
public func moveRight(sender: AnyObject?)
public func moveBackward(sender: AnyObject?)
public func moveLeft(sender: AnyObject?)
public func moveUp(sender: AnyObject?)
public func moveDown(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 scrollPageUp(sender: AnyObject?)
public func scrollPageDown(sender: AnyObject?)
public func scrollLineUp(sender: AnyObject?)
public func scrollLineDown(sender: AnyObject?)
public func scrollToBeginningOfDocument(sender: AnyObject?)
public func scrollToEndOfDocument(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 deleteForward(sender: AnyObject?)
public func deleteBackward(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?)
*/
} }
/* The receiver inserts aString replacing the content specified by replacementRange. aString can be either an NSString or NSAttributedString instance. selectedRange specifies the selection inside the string being inserted; hence, the location is relative to the beginning of aString. When aString is an NSString, the receiver is expected to render the marked text with distinguishing appearance (i.e. NSTextView renders with -markedTextAttributes). /* The receiver inserts aString replacing the content specified by replacementRange. aString can be either an NSString or NSAttributedString instance. selectedRange specifies the selection inside the string being inserted; hence, the location is relative to the beginning of aString. When aString is an NSString, the receiver is expected to render the marked text with distinguishing appearance (i.e. NSTextView renders with -markedTextAttributes).
@ -162,13 +54,13 @@ public class InputTestView: NSView, NSTextInputClient {
/* Returns the marked range. Returns {NSNotFound, 0} if no marked range. /* Returns the marked range. Returns {NSNotFound, 0} if no marked range.
*/ */
public func markedRange() -> NSRange { public func markedRange() -> NSRange {
Swift.print("\(#function): ")
if let markedText = self.markedText { if let markedText = self.markedText {
return NSRange(location: self.text.characters.count, length: markedText.characters.count) Swift.print("\(#function): returning \(NSRange(location: 0, length: 1))")
return NSRange(location: 0, length: 1)
} }
return NSRange(location: NSNotFound, length: 1) Swift.print("\(#function): returning \(NSRange(location: NSNotFound, length: 0))")
return NSRange(location: NSNotFound, length: 0)
} }
/* Returns whether or not the receiver has marked text. /* Returns whether or not the receiver has marked text.
@ -182,7 +74,7 @@ public class InputTestView: NSView, NSTextInputClient {
/* Returns attributed string specified by aRange. It may return nil. If non-nil return value and actualRange is non-NULL, it contains the actual range for the return value. The range can be adjusted from various reasons (i.e. adjust to grapheme cluster boundary, performance optimization, etc). /* Returns attributed string specified by aRange. It may return nil. If non-nil return value and actualRange is non-NULL, it contains the actual range for the return value. The range can be adjusted from various reasons (i.e. adjust to grapheme cluster boundary, performance optimization, etc).
*/ */
public func attributedSubstringForProposedRange(aRange: NSRange, actualRange: NSRangePointer) -> NSAttributedString? { public func attributedSubstringForProposedRange(aRange: NSRange, actualRange: NSRangePointer) -> NSAttributedString? {
Swift.print("\(#function): \(aRange), \(actualRange)") Swift.print("\(#function): \(aRange), \(actualRange[0])")
return NSAttributedString(string: "") return NSAttributedString(string: "")
} }
@ -197,11 +89,12 @@ public class InputTestView: NSView, NSTextInputClient {
*/ */
public func firstRectForCharacterRange(aRange: NSRange, actualRange: NSRangePointer) -> NSRect { public func firstRectForCharacterRange(aRange: NSRange, actualRange: NSRangePointer) -> NSRect {
if actualRange != nil { if actualRange != nil {
Swift.print("\(#function): \(aRange), \(actualRange[0])") // Swift.print("\(#function): \(aRange), \(actualRange[0])")
} else { } else {
Swift.print("\(#function): \(aRange), nil") // Swift.print("\(#function): \(aRange), nil")
} }
Swift.print("\(#function): \(aRange), \(actualRange[0])")
let resultInSelf = NSRect(x: 0, y: 0, width: 10, height: 10) let resultInSelf = NSRect(x: 0, y: 0, width: 10, height: 10)
let result = self.window?.convertRectToScreen(self.convertRect(resultInSelf, toView: nil)) let result = self.window?.convertRectToScreen(self.convertRect(resultInSelf, toView: nil))
@ -243,15 +136,15 @@ public class InputTestView: NSView, NSTextInputClient {
let charsIgnoringModifiers = shift || capslock ? theEvent.charactersIgnoringModifiers!.lowercaseString let charsIgnoringModifiers = shift || capslock ? theEvent.charactersIgnoringModifiers!.lowercaseString
: theEvent.charactersIgnoringModifiers! : theEvent.charactersIgnoringModifiers!
Swift.print("characters: \(chars)")// = " + String(format:"%x", theEvent.characters!.unicodeScalars.first!.value)) // Swift.print("characters: \(chars)")// = " + String(format:"%x", theEvent.characters!.unicodeScalars.first!.value))
Swift.print("characters ign: \(charsIgnoringModifiers)")// = " + String(format:"%x", theEvent.charactersIgnoringModifiers!.unicodeScalars.first!.value)) // Swift.print("characters ign: \(charsIgnoringModifiers)")// = " + String(format:"%x", theEvent.charactersIgnoringModifiers!.unicodeScalars.first!.value))
// Swift.print(String(format: "keycode: %x", theEvent.keyCode)) // Swift.print(String(format: "keycode: %x", theEvent.keyCode))
Swift.print("shift: \(shift), command: \(command), control: \(control), option: \(option)") // Swift.print("shift: \(shift), command: \(command), control: \(control), option: \(option)")
let inputContext = NSTextInputContext.currentInputContext()! let inputContext = NSTextInputContext.currentInputContext()!
let handled = inputContext.handleEvent(theEvent) let handled = inputContext.handleEvent(theEvent)
if handled { if handled {
Swift.print("Cocoa handled it") // Swift.print("Cocoa handled it")
} }
// self.text += theEvent.charactersIgnoringModifiers! // self.text += theEvent.charactersIgnoringModifiers!
@ -264,6 +157,6 @@ public class InputTestView: NSView, NSTextInputClient {
} }
private func vimInput(string: String) { private func vimInput(string: String) {
Swift.print("### vim input: \(string)") // Swift.print("### vim input: \(string)")
} }
} }

View File

@ -72,6 +72,11 @@ public class NeoVimView: NSView {
let xpc: NeoVimXpc let xpc: NeoVimXpc
var markedText: String? var markedText: String?
var markedPosition = Position.null {
didSet {
// Swift.print("\(self.markedPosition)")
}
}
var keyDownDone = true var keyDownDone = true
var cellSize = CGSize.zero var cellSize = CGSize.zero

View File

@ -32,6 +32,181 @@ extension NeoVimView: NSTextInputClient {
self.keyDownDone = true self.keyDownDone = true
} }
public func insertText(aString: AnyObject, replacementRange: NSRange) {
NSLog("\(#function): \(replacementRange): \(aString)")
switch aString {
case let string as String:
self.xpc.vimInput(self.vimPlainString(string))
case let attributedString as NSAttributedString:
self.xpc.vimInput(self.vimPlainString(attributedString.string))
default:
break;
}
// unmarkText()
self.markedText = nil
self.markedPosition = Position.null
// TODO: necessary?
self.setNeedsDisplayInRect(self.cellRect(row: self.grid.position.row, column: self.grid.position.column))
self.keyDownDone = true
}
public override func doCommandBySelector(aSelector: Selector) {
// NSLog("\(#function): "\(aSelector)")
// TODO: handle when -> delete
if self.respondsToSelector(aSelector) {
Swift.print("\(#function): calling \(aSelector)")
self.performSelector(aSelector, withObject: self)
self.keyDownDone = true
return
}
// NSLog("\(#function): "\(aSelector) not implemented, forwarding input to vim")
self.keyDownDone = false
}
public func setMarkedText(aString: AnyObject, selectedRange: NSRange, replacementRange: NSRange) {
if self.markedText == nil {
self.markedPosition = self.grid.position
}
switch aString {
case let string as String:
self.markedText = string
case let attributedString as NSAttributedString:
self.markedText = attributedString.string
default:
self.markedText = String(aString) // should not occur
}
NSLog("\(#function): \(self.markedText), \(selectedRange), \(replacementRange)")
self.xpc.vimInputMarkedText(self.markedText!)
self.keyDownDone = true
}
public func unmarkText() {
NSLog("\(#function): ")
self.markedText = nil
self.markedPosition = Position.null
// TODO: necessary?
self.setNeedsDisplayInRect(self.cellRect(row: self.grid.position.row, column: self.grid.position.column))
self.keyDownDone = true
}
/// Return the current selection (or the position of the cursor with empty-length range). For example when you enter
/// "Cmd-Ctrl-Return" you'll get the Emoji-popup at the rect by firstRectForCharacterRange(actualRange:) where the
/// first range is the result of this method.
public func selectedRange() -> NSRange {
// if self.markedText == nil {
// let result = NSRange(location: self.grid.singleIndexFrom(self.grid.position), length: 0)
// NSLog("\(#function): \(result)")
// return result
// }
// FIXME: do we have to handle positions at the column borders?
if self.grid.isPreviousCellEmpty(self.grid.position) {
let result = NSRange(
location: self.grid.singleIndexFrom(
Position(row: self.grid.position.row, column: self.grid.position.column - 1)
),
length: 0
)
NSLog("\(#function): \(result)")
return result
}
let result = NSRange(location: self.grid.singleIndexFrom(self.grid.position), length: 0)
NSLog("\(#function): \(result)")
return result
}
public func markedRange() -> NSRange {
// FIXME: do we have to handle positions at the column borders?
if let markedText = self.markedText {
let result = NSRange(location: self.grid.singleIndexFrom(self.markedPosition),
length: markedText.characters.count)
NSLog("\(#function): \(result)")
return result
}
NSLog("\(#function): returning empty range")
return NSRange(location: NSNotFound, length: 0)
}
public func hasMarkedText() -> Bool {
let result = self.markedText != nil
// NSLog("\(#function): "returning \(result)")
return result
}
// FIXME: REFACTOR and take into account the "return nil"-case
public func attributedSubstringForProposedRange(aRange: NSRange, actualRange: NSRangePointer) -> NSAttributedString? {
// NSLog("\(#function): \(aRange), \(actualRange[0])")
// first check whether the first cell is empty and if so, jump one character backward
var length = aRange.length
var location = aRange.location
var position = self.grid.positionFromSingleIndex(aRange.location)
if self.grid.isCellEmpty(position) {
length += 1
location -= 1
position = self.grid.positionFromSingleIndex(location)
}
// check whether the range extend to multiple lines
let multipleLines = position.column + length >= self.grid.size.width
if !multipleLines {
// FIXME: do we have to handle position.column + aRange.length >= self.grid.width?
let string = self.grid.cells[position.row][position.column...(position.column + length)].reduce("") {
$0 + $1.string
}
actualRange[0].length = string.characters.count
NSLog("\(#function): \(aRange), \(actualRange[0]): \(string)")
return NSAttributedString(string: string)
}
// TODO: 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)")
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 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 result = self.window?.convertRectToScreen(self.convertRect(resultInSelf, toView: nil))
return result!
}
public func characterIndexForPoint(aPoint: NSPoint) -> Int {
NSLog("\(#function): \(aPoint)")
return 1
}
private func vimModifierFlags(modifierFlags: NSEventModifierFlags) -> String { private func vimModifierFlags(modifierFlags: NSEventModifierFlags) -> String {
var result = "" var result = ""
@ -55,114 +230,6 @@ extension NeoVimView: NSTextInputClient {
return result return result
} }
public func insertText(aString: AnyObject, replacementRange: NSRange) {
// Swift.print("\(#function): \(aString), \(replacementRange)")
switch aString {
case let string as String:
self.xpc.vimInput(self.vimPlainString(string))
case let attributedString as NSAttributedString:
self.xpc.vimInput(self.vimPlainString(attributedString.string))
default:
break;
}
self.markedText = nil
self.keyDownDone = true
}
public override func doCommandBySelector(aSelector: Selector) {
Swift.print("\(#function): \(aSelector)")
// TODO: handle when -> delete
if self.respondsToSelector(aSelector) {
Swift.print("\(#function): calling \(aSelector)")
self.performSelector(aSelector, withObject: self)
self.keyDownDone = true
return
}
Swift.print("\(#function): \(aSelector) not implemented, forwarding input to vim")
self.keyDownDone = false
}
public func setMarkedText(aString: AnyObject, selectedRange: NSRange, replacementRange: NSRange) {
Swift.print("\(#function): \(aString), \(selectedRange), \(replacementRange)")
switch aString {
case let string as String:
self.markedText = string
case let attributedString as NSAttributedString:
self.markedText = attributedString.string
default:
self.markedText = String(aString) // should not occur
}
self.xpc.vimInputMarkedText(self.markedText!)
self.keyDownDone = true
}
public func unmarkText() {
Swift.print("\(#function): ")
self.markedText = nil
self.setNeedsDisplayInRect(self.cellRect(row: self.grid.position.row, column: self.grid.position.column))
self.keyDownDone = true
}
/// Return the current selection (or the position of the cursor with empty-length range). For example when you enter
/// "Cmd-Ctrl-Return" you'll get the Emoji-popup at the rect by firstRectForCharacterRange(actualRange:) where the
/// first range is the result of this method.
public func selectedRange() -> NSRange {
let result = NSRange(location: 13, length: 0)
Swift.print("\(#function): returning \(result)")
return result
}
public func markedRange() -> NSRange {
Swift.print("\(#function): ")
if let markedText = self.markedText {
// return NSRange(location: self.text.characters.count, length: markedText.characters.count)
}
return NSRange(location: NSNotFound, length: 0)
}
public func hasMarkedText() -> Bool {
let result = self.markedText != nil
// Swift.print("\(#function): returning \(result)")
return result
}
public func attributedSubstringForProposedRange(aRange: NSRange, actualRange: NSRangePointer) -> NSAttributedString? {
Swift.print("\(#function): \(aRange), \(actualRange)")
return NSAttributedString(string: "t")
}
public func validAttributesForMarkedText() -> [String] {
// Swift.print("\(#function): ")
return []
}
public func firstRectForCharacterRange(aRange: NSRange, actualRange: NSRangePointer) -> NSRect {
if actualRange != nil {
Swift.print("\(#function): \(aRange), \(actualRange[0])")
} else {
Swift.print("\(#function): \(aRange), nil")
}
let resultInSelf = NSRect(x: 0, y: 0, width: 10, height: 10)
let result = self.window?.convertRectToScreen(self.convertRect(resultInSelf, toView: nil))
return result!
}
public func characterIndexForPoint(aPoint: NSPoint) -> Int {
Swift.print("\(#function): \(aPoint)")
return 1
}
/* /*
public func moveWordForward(sender: AnyObject?) public func moveWordForward(sender: AnyObject?)
public func moveWordBackward(sender: AnyObject?) public func moveWordBackward(sender: AnyObject?)

View File

@ -14,7 +14,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
height: CGFloat(height) * self.cellSize.height height: CGFloat(height) * self.cellSize.height
) )
Swift.print("### resize to \(width):\(height)") // Swift.print("### resize to \(width):\(height)")
self.grid.resize(Size(width: Int(width), height: Int(height))) self.grid.resize(Size(width: Int(width), height: Int(height)))
self.delegate?.resizeToSize(rectSize) self.delegate?.resizeToSize(rectSize)
} }
@ -22,7 +22,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
public func clear() { public func clear() {
DispatchUtils.gui { DispatchUtils.gui {
Swift.print("### clear") // Swift.print("### clear")
self.grid.clear() self.grid.clear()
self.needsDisplay = true self.needsDisplay = true
} }
@ -30,7 +30,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
public func eolClear() { public func eolClear() {
DispatchUtils.gui { DispatchUtils.gui {
Swift.print("### eol clear") // Swift.print("### eol clear")
self.grid.eolClear() self.grid.eolClear()
let origin = self.positionOnView(self.grid.position.row, column: self.grid.position.column) let origin = self.positionOnView(self.grid.position.row, column: self.grid.position.column)
@ -45,10 +45,10 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
public func cursorGotoRow(row: Int32, column: Int32) { public func cursorGotoRow(row: Int32, column: Int32) {
DispatchUtils.gui { DispatchUtils.gui {
Swift.print("### goto: \(row):\(column)") NSLog("\(#function): \(row):\(column)")
self.setCursorNeedsDisplay() self.setCursorNeedsDisplay(self.grid.position)
self.grid.goto(Position(row: Int(row), column: Int(column))) self.grid.goto(Position(row: Int(row), column: Int(column)))
self.setCursorNeedsDisplay() self.setCursorNeedsDisplay(self.grid.position)
} }
} }
@ -73,11 +73,11 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
} }
public func modeChange(mode: Int32) { public func modeChange(mode: Int32) {
Swift.print("### mode change to: \(String(format: "%04X", mode))") // Swift.print("### mode change to: \(String(format: "%04X", mode))")
} }
public func setScrollRegionToTop(top: Int32, bottom: Int32, left: Int32, right: Int32) { public func setScrollRegionToTop(top: Int32, bottom: Int32, left: Int32, right: Int32) {
Swift.print("### set scroll region: \(top), \(bottom), \(left), \(right)") // Swift.print("### set scroll region: \(top), \(bottom), \(left), \(right)")
DispatchUtils.gui { DispatchUtils.gui {
let region = Region(top: Int(top), bottom: Int(bottom), left: Int(left), right: Int(right)) let region = Region(top: Int(top), bottom: Int(bottom), left: Int(left), right: Int(right))
self.grid.setScrollRegion(region) self.grid.setScrollRegion(region)
@ -86,7 +86,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
} }
public func scroll(count: Int32) { public func scroll(count: Int32) {
Swift.print("### scroll count: \(count)") // Swift.print("### scroll count: \(count)")
DispatchUtils.gui { DispatchUtils.gui {
self.grid.scroll(Int(count)) self.grid.scroll(Int(count))
@ -112,15 +112,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
if string.characters.count == 0 { if string.characters.count == 0 {
self.setNeedsDisplayAt(row: curPos.row, column: max(curPos.column - 1, 0)) self.setNeedsDisplayAt(row: curPos.row, column: max(curPos.column - 1, 0))
} }
self.setCursorNeedsDisplay() self.setCursorNeedsDisplay(self.grid.position)
}
}
private func setCursorNeedsDisplay() {
let position = self.grid.position
self.setNeedsDisplayAt(position: position)
if self.grid.isNextCellEmpty(position) {
self.setNeedsDisplayAt(position: self.grid.nextCellPosition(position))
} }
} }
@ -134,7 +126,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
if markedText.characters.count == 0 { if markedText.characters.count == 0 {
self.setNeedsDisplayAt(row: curPos.row, column: max(curPos.column - 1, 0)) self.setNeedsDisplayAt(row: curPos.row, column: max(curPos.column - 1, 0))
} }
self.setCursorNeedsDisplay() self.setCursorNeedsDisplay(self.grid.position)
} }
} }
@ -143,7 +135,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
// Swift.print("\(#function): \(row):\(column)") // Swift.print("\(#function): \(row):\(column)")
self.grid.unmarkCell(Position(row: Int(row), column: Int(column))) self.grid.unmarkCell(Position(row: Int(row), column: Int(column)))
self.setNeedsDisplayAt(row: Int(row), column: Int(column)) self.setNeedsDisplayAt(row: Int(row), column: Int(column))
self.setCursorNeedsDisplay() self.setCursorNeedsDisplay(self.grid.position)
} }
} }
@ -197,7 +189,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
} }
public func stop() { public func stop() {
Swift.print("### stop") // Swift.print("### stop")
} }
private func setNeedsDisplayAt(position position: Position) { private func setNeedsDisplayAt(position position: Position) {
@ -208,4 +200,11 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
// Swift.print("\(#function): \(row):\(column)") // Swift.print("\(#function): \(row):\(column)")
self.setNeedsDisplayInRect(self.cellRect(row: row, column: column)) self.setNeedsDisplayInRect(self.cellRect(row: row, column: column))
} }
private func setCursorNeedsDisplay(position: Position) {
self.setNeedsDisplayAt(position: position)
if self.grid.isNextCellEmpty(position) {
self.setNeedsDisplayAt(position: self.grid.nextCellPosition(position))
}
}
} }