mirror of
https://github.com/qvacua/vimr.git
synced 2024-12-28 00:06:50 +03:00
1d1c46c3fc
- 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...
324 lines
12 KiB
Swift
324 lines
12 KiB
Swift
/**
|
|
* Tae Won Ha - http://taewon.de - @hataewon
|
|
* See LICENSE
|
|
*/
|
|
|
|
import Cocoa
|
|
|
|
extension NeoVimView: NSTextInputClient {
|
|
|
|
override public func keyDown(event: NSEvent) {
|
|
self.keyDownDone = false
|
|
|
|
let context = NSTextInputContext.currentInputContext()!
|
|
let cocoaHandledEvent = context.handleEvent(event)
|
|
if self.keyDownDone && cocoaHandledEvent {
|
|
return
|
|
}
|
|
|
|
let modifierFlags = event.modifierFlags
|
|
let capslock = modifierFlags.contains(.AlphaShiftKeyMask)
|
|
let shift = modifierFlags.contains(.ShiftKeyMask)
|
|
let chars = event.characters!
|
|
let charsIgnoringModifiers = shift || capslock ? event.charactersIgnoringModifiers!.lowercaseString
|
|
: event.charactersIgnoringModifiers!
|
|
|
|
let vimModifiers = self.vimModifierFlags(modifierFlags)
|
|
if vimModifiers.characters.count > 0 {
|
|
self.xpc.vimInput(self.vimNamedKeys(vimModifiers + charsIgnoringModifiers))
|
|
} else {
|
|
self.xpc.vimInput(self.vimPlainString(chars))
|
|
}
|
|
|
|
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 {
|
|
var result = ""
|
|
|
|
let control = modifierFlags.contains(.ControlKeyMask)
|
|
let option = modifierFlags.contains(.AlternateKeyMask)
|
|
let command = modifierFlags.contains(.CommandKeyMask)
|
|
|
|
if control {
|
|
result += "C-"
|
|
}
|
|
|
|
if option {
|
|
result += "M-"
|
|
}
|
|
|
|
if command {
|
|
result += "D-"
|
|
}
|
|
|
|
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?)
|
|
*/
|
|
}
|