1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-12-29 00:34:26 +03:00

Make resizing NeoVimView work

- live resizing is not yet activated, but can be easily done
- @autoreleasepool-block for each UI callback and for each key input is
  ugly...
This commit is contained in:
Tae Won Ha 2016-07-04 22:06:39 +02:00
parent b0e82ff005
commit 07ac09e95f
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
8 changed files with 146 additions and 66 deletions

View File

@ -19,6 +19,7 @@
- (void)deleteCharacters:(NSInteger)count;
- (void)resizeToWidth:(int)width height:(int)height;
- (void)forceRedraw;
- (void)debug1;

View File

@ -18,6 +18,7 @@
- (void)vimInput:(NSString *_Nonnull)input;
- (void)vimInputMarkedText:(NSString *_Nonnull)markedText;
- (void)deleteCharacters:(NSInteger)count;
- (void)forceRedraw;
- (void)resizeToWidth:(int)width height:(int)height;

View File

@ -19,6 +19,7 @@
#import <nvim/event/signal.h>
#import <nvim/main.h>
#import <nvim/cursor.h>
#import <nvim/screen.h>
#define pun_type(t, x) (*((t *)(&x)))
@ -75,8 +76,20 @@ static inline int screen_cursor_column() {
return curwin->w_wincol + curwin->w_wcol;
}
static void xpc_async(void (^block)()) {
dispatch_async(_queue, block);
// TODO: Is it possible to optimize away @autoreleasepool?
static inline void xpc_sync(void (^block)()) {
dispatch_sync(_queue, ^{
@autoreleasepool {
block();
}
});
}
static void set_ui_size(UIBridgeData *bridge, int width, int height) {
bridge->ui->width = width;
bridge->ui->height = height;
bridge->bridge.width = width;
bridge->bridge.height = height;
}
static void sigcont_cb(SignalWatcher *watcher __unused, int signum __unused, void *data) {
@ -102,8 +115,7 @@ static void osx_xpc_ui_main(UIBridgeData *bridge, UI *ui) {
signal_watcher_init(_xpc_ui_data->loop, &_xpc_ui_data->cont_handle, _xpc_ui_data);
signal_watcher_start(&_xpc_ui_data->cont_handle, sigcont_cb, SIGCONT);
bridge->bridge.width = 30;
bridge->bridge.height = 10;
set_ui_size(bridge, 30, 15);
_xpc_ui_data->stop = false;
CONTINUE(bridge);
@ -141,86 +153,86 @@ static void suspend_event(void **argv) {
}
static void xpc_ui_resize(UI *ui __unused, int width, int height) {
xpc_async(^{
xpc_sync(^{
[_neo_vim_osx_ui resizeToWidth:width height:height];
});
}
static void xpc_ui_clear(UI *ui __unused) {
xpc_async(^{
xpc_sync(^{
[_neo_vim_osx_ui clear];
});
}
static void xpc_ui_eol_clear(UI *ui __unused) {
xpc_async(^{
xpc_sync(^{
[_neo_vim_osx_ui eolClear];
});
}
static void xpc_ui_cursor_goto(UI *ui __unused, int row, int col) {
xpc_async(^{
xpc_sync(^{
// log4Debug("%d:%d", row, col);
_put_row = row;
_put_column = col;
[_neo_vim_osx_ui gotoPosition:(Position) { .row = row, .column = col }
screenCursor:(Position) { .row = screen_cursor_row(), .column = screen_cursor_column() }
bufferCursor:(Position) { .row = curwin->w_cursor.lnum - 1, .column = curwin->w_cursor.col }];
[_neo_vim_osx_ui gotoPosition:(Position) {.row = row, .column = col}
screenCursor:(Position) {.row = screen_cursor_row(), .column = screen_cursor_column()}
bufferCursor:(Position) {.row = curwin->w_cursor.lnum - 1, .column = curwin->w_cursor.col}];
});
}
static void xpc_ui_update_menu(UI *ui __unused) {
xpc_async(^{
xpc_sync(^{
[_neo_vim_osx_ui updateMenu];
});
}
static void xpc_ui_busy_start(UI *ui __unused) {
xpc_async(^{
xpc_sync(^{
[_neo_vim_osx_ui busyStart];
});
}
static void xpc_ui_busy_stop(UI *ui __unused) {
xpc_async(^{
xpc_sync(^{
[_neo_vim_osx_ui busyStop];
});
}
static void xpc_ui_mouse_on(UI *ui __unused) {
xpc_async(^{
xpc_sync(^{
[_neo_vim_osx_ui mouseOn];
});
}
static void xpc_ui_mouse_off(UI *ui __unused) {
xpc_async(^{
xpc_sync(^{
[_neo_vim_osx_ui mouseOff];
});
}
static void xpc_ui_mode_change(UI *ui __unused, int mode) {
xpc_async(^{
xpc_sync(^{
[_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(^{
xpc_sync(^{
[_neo_vim_osx_ui setScrollRegionToTop:top bottom:bot left:left right:right];
});
}
static void xpc_ui_scroll(UI *ui __unused, int count) {
xpc_async(^{
xpc_sync(^{
[_neo_vim_osx_ui scroll:count];
});
}
static void xpc_ui_highlight_set(UI *ui __unused, HlAttrs attrs) {
xpc_async(^{
xpc_sync(^{
FontTrait trait = FontTraitNone;
if (attrs.italic) {
trait |= FontTraitItalic;
@ -249,8 +261,9 @@ static void xpc_ui_highlight_set(UI *ui __unused, HlAttrs attrs) {
}
static void xpc_ui_put(UI *ui __unused, uint8_t *str, size_t len) {
xpc_async(^{
xpc_sync(^{
NSString *string = [[NSString alloc] initWithBytes:str length:len encoding:NSUTF8StringEncoding];
// printf("%s", [string cStringUsingEncoding:NSUTF8StringEncoding]);
if (_marked_text != nil && _marked_row == _put_row && _marked_column == _put_column) {
// log4Debug("putting marked text: '%@'", string);
@ -269,25 +282,25 @@ static void xpc_ui_put(UI *ui __unused, uint8_t *str, size_t len) {
}
static void xpc_ui_bell(UI *ui __unused) {
xpc_async(^{
xpc_sync(^{
[_neo_vim_osx_ui bell];
});
}
static void xpc_ui_visual_bell(UI *ui __unused) {
xpc_async(^{
xpc_sync(^{
[_neo_vim_osx_ui visualBell];
});
}
static void xpc_ui_flush(UI *ui __unused) {
xpc_async(^{
xpc_sync(^{
[_neo_vim_osx_ui flush];
});
}
static void xpc_ui_update_fg(UI *ui __unused, int fg) {
xpc_async(^{
xpc_sync(^{
if (fg == -1) {
[_neo_vim_osx_ui updateForeground:_default_foreground];
return;
@ -299,7 +312,7 @@ static void xpc_ui_update_fg(UI *ui __unused, int fg) {
}
static void xpc_ui_update_bg(UI *ui __unused, int bg) {
xpc_async(^{
xpc_sync(^{
if (bg == -1) {
[_neo_vim_osx_ui updateBackground:_default_background];
return;
@ -311,7 +324,7 @@ static void xpc_ui_update_bg(UI *ui __unused, int bg) {
}
static void xpc_ui_update_sp(UI *ui __unused, int sp) {
xpc_async(^{
xpc_sync(^{
if (sp == -1) {
[_neo_vim_osx_ui updateSpecial:_default_special];
return;
@ -323,7 +336,7 @@ static void xpc_ui_update_sp(UI *ui __unused, int sp) {
}
static void xpc_ui_suspend(UI *ui __unused) {
xpc_async(^{
xpc_sync(^{
[_neo_vim_osx_ui suspend];
XpcUiData *data = ui->data;
@ -336,7 +349,7 @@ static void xpc_ui_suspend(UI *ui __unused) {
}
static void xpc_ui_set_title(UI *ui __unused, char *title) {
xpc_async(^{
xpc_sync(^{
NSString *string = [[NSString alloc] initWithCString:title encoding:NSUTF8StringEncoding];
[_neo_vim_osx_ui setTitle:string];
[string release];
@ -344,7 +357,7 @@ static void xpc_ui_set_title(UI *ui __unused, char *title) {
}
static void xpc_ui_set_icon(UI *ui __unused, char *icon) {
xpc_async(^{
xpc_sync(^{
NSString *string = [[NSString alloc] initWithCString:icon encoding:NSUTF8StringEncoding];
[_neo_vim_osx_ui setIcon:string];
[string release];
@ -352,7 +365,7 @@ static void xpc_ui_set_icon(UI *ui __unused, char *icon) {
}
static void xpc_ui_stop(UI *ui __unused) {
xpc_async(^{
xpc_sync(^{
[_neo_vim_osx_ui stop];
XpcUiData *data = (XpcUiData *) ui->data;
@ -401,20 +414,28 @@ void custom_ui_start(void) {
ui_bridge_attach(ui, osx_xpc_ui_main, osx_xpc_ui_scheduler);
}
static void force_redraw(void **argv __unused) {
must_redraw = CLEAR;
update_screen(0);
}
static void refresh_ui(void **argv __unused) {
ui_refresh();
}
// TODO: optimize away @autoreleasepool?
static void neovim_input(void **argv) {
NSString *input = (NSString *) argv[0];
@autoreleasepool {
NSString *input = (NSString *) argv[0];
// FIXME: check the length of the consumed bytes by neovim and if not fully consumed, call vim_input again.
vim_input((String) {
.data = (char *) input.UTF8String,
.size = [input lengthOfBytesUsingEncoding:NSUTF8StringEncoding]
});
// FIXME: check the length of the consumed bytes by neovim and if not fully consumed, call vim_input again.
vim_input((String) {
.data = (char *) input.UTF8String,
.size = [input lengthOfBytesUsingEncoding:NSUTF8StringEncoding]
});
[input release]; // retain in loop_schedule(&main_loop, ...) (in _queue) somewhere
[input release]; // retain in loop_schedule(&main_loop, ...) (in _queue) somewhere
}
}
@implementation NeoVimXpcImpl
@ -448,6 +469,7 @@ static void neovim_input(void **argv) {
[ui retain];
_neo_vim_osx_ui = ui;
[_neo_vim_osx_ui neoVimUiIsReady];
_backspace = [[NSString alloc] initWithString:@"<BS>"];
@ -468,7 +490,7 @@ static void neovim_input(void **argv) {
}
- (void)deleteCharacters:(NSInteger)count {
xpc_async(^{
xpc_sync(^{
_marked_delta = 0;
// Very ugly: When we want to have the Hanja for , Cocoa first finalizes , then sets the Hanja as marked text.
@ -495,22 +517,20 @@ static void neovim_input(void **argv) {
});
}
- (void)forceRedraw {
loop_schedule(&main_loop, event_create(1, force_redraw, 0));
}
- (void)resizeToWidth:(int)width height:(int)height {
xpc_async(^{
xpc_sync(^{
// see sigwinch_cb() and update_size() in tui.c
UI *ui = _xpc_ui_data->bridge->ui;
ui->width = width;
ui->height = height;
_xpc_ui_data->bridge->bridge.width = width;
_xpc_ui_data->bridge->bridge.height = height;
set_ui_size(_xpc_ui_data->bridge, width, height);
loop_schedule(&main_loop, event_create(1, refresh_ui, 0));
});
}
- (void)vimInput:(NSString *_Nonnull)input {
xpc_async(^{
xpc_sync(^{
if (_marked_text == nil) {
loop_schedule(&main_loop, event_create(1, neovim_input, 1, [input retain])); // release in neovim_input
return;
@ -535,7 +555,7 @@ static void neovim_input(void **argv) {
}
- (void)vimInputMarkedText:(NSString *_Nonnull)markedText {
xpc_async(^{
xpc_sync(^{
if (_marked_text == nil) {
_marked_row = _put_row;
_marked_column = _put_column + _marked_delta;

View File

@ -32,6 +32,8 @@ typedef struct {
@protocol NeoVimUiBridgeProtocol <NSObject>
- (void)neoVimUiIsReady;
/**
* NeoVim has set the size of its screen to rows X columns. The view must be resized accordingly.
*/

View File

@ -66,9 +66,9 @@ public class NeoVimView: NSView {
// FIXME: resize and redraw
}
}
private let xOffset = CGFloat(4)
private let yOffSet = CGFloat(4)
var xOffset = CGFloat(0)
var yOffset = CGFloat(0)
private let drawer: TextDrawer
@ -108,11 +108,44 @@ public class NeoVimView: NSView {
Swift.print(self.grid)
}
// override public func setFrameSize(newSize: NSSize) {
// super.setFrameSize(newSize)
//
// // initial resizing is done when grid has data
// guard self.grid.hasData else {
// return
// }
//
// self.resizeNeoVimUiTo(size: newSize)
// }
override public func viewDidEndLiveResize() {
super.viewDidEndLiveResize()
self.resizeNeoVimUiTo(size: self.bounds.size)
}
func resizeNeoVimUiTo(size size: CGSize) {
NSLog("\(#function): \(size)")
let discreteSize = Size(width: Int(floor(size.width / self.cellSize.width)),
height: Int(floor(size.height / self.cellSize.height)))
self.xOffset = floor((size.width - self.cellSize.width * CGFloat(discreteSize.width)) / 2)
self.yOffset = floor((size.height - self.cellSize.height * CGFloat(discreteSize.height)) / 2)
self.xpc.resizeToWidth(Int32(discreteSize.width), height: Int32(discreteSize.height))
}
override public func drawRect(dirtyUnionRect: NSRect) {
guard self.grid.hasData else {
return
}
if self.inLiveResize {
NSColor.lightGrayColor().set()
dirtyUnionRect.fill()
return
}
// NSLog("\(#function): \(dirtyUnionRect)")
let context = NSGraphicsContext.currentContext()!.CGContext
@ -225,7 +258,7 @@ public class NeoVimView: NSView {
func pointInView(row: Int, column: Int) -> CGPoint {
return CGPoint(
x: CGFloat(column) * self.cellSize.width + self.xOffset,
y: self.frame.size.height - CGFloat(row) * self.cellSize.height - self.cellSize.height - self.yOffSet
y: self.frame.size.height - CGFloat(row) * self.cellSize.height - self.cellSize.height - self.yOffset
)
}
@ -248,7 +281,7 @@ public class NeoVimView: NSView {
return CGRect(
x: left * self.cellSize.width + self.xOffset,
y: (CGFloat(self.grid.size.height) - bottom) * self.cellSize.height - self.yOffSet,
y: (CGFloat(self.grid.size.height) - bottom) * self.cellSize.height - self.yOffset,
width: width * self.cellSize.width,
height: height * self.cellSize.height
)

View File

@ -140,6 +140,7 @@ extension NeoVimView: NSTextInputClient {
}
// FIXME: take into account the "return nil"-case
// FIXME: just fix me, PLEASE...
public func attributedSubstringForProposedRange(aRange: NSRange, actualRange: NSRangePointer) -> NSAttributedString? {
// NSLog("\(#function): \(aRange), \(actualRange[0])")
if aRange.location == NSNotFound {
@ -154,6 +155,10 @@ extension NeoVimView: NSTextInputClient {
// we only support last marked text, thus fill dummy characters when Cocoa asks for more characters than marked...
let fillCount = aRange.length - lastMarkedText.characters.count
guard fillCount >= 0 else {
return nil
}
let fillChars = Array(0..<fillCount).reduce("") { (result, _) in return result + " " }
// NSLog("\(#function): \(aRange), \(actualRange[0]): \(fillChars + lastMarkedText)")

View File

@ -7,20 +7,23 @@ import Cocoa
extension NeoVimView: NeoVimUiBridgeProtocol {
public func neoVimUiIsReady() {
DispatchUtils.gui {
NSLog("\(#function): \(self.frame)")
self.resizeNeoVimUiTo(size: self.frame.size)
}
}
public func resizeToWidth(width: Int32, height: Int32) {
DispatchUtils.gui {
let rectSize = CGSize(
width: CGFloat(width) * self.cellSize.width,
height: CGFloat(height) * self.cellSize.height
)
// NSLog("\(#function): \(width):\(height)")
self.grid.resize(Size(width: Int(width), height: Int(height)))
self.delegate?.resizeToSize(rectSize)
// TODO: set needs display?
self.needsDisplay = true
}
}
public func clear() {
//if self.inLiveResize { return }
DispatchUtils.gui {
self.grid.clear()
self.needsDisplay = true
@ -28,6 +31,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
}
public func eolClear() {
//if self.inLiveResize { return }
DispatchUtils.gui {
self.grid.eolClear()
@ -42,6 +46,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
}
public func gotoPosition(position: Position, screenCursor: Position, bufferCursor: Position) {
//if self.inLiveResize { return }
DispatchUtils.gui {
// NSLog("\(#function): \(position), \(screenCursor), \(bufferCursor)")
@ -72,6 +77,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
}
public func setScrollRegionToTop(top: Int32, bottom: Int32, left: Int32, right: Int32) {
//if self.inLiveResize { return }
DispatchUtils.gui {
let region = Region(top: Int(top), bottom: Int(bottom), left: Int(left), right: Int(right))
self.grid.setScrollRegion(region)
@ -80,6 +86,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
}
public func scroll(count: Int32) {
//if self.inLiveResize { return }
DispatchUtils.gui {
self.grid.scroll(Int(count))
self.setNeedsDisplay(region: self.grid.region)
@ -87,12 +94,14 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
}
public func highlightSet(attrs: CellAttributes) {
//if self.inLiveResize { return }
DispatchUtils.gui {
self.grid.attrs = attrs
}
}
public func put(string: String) {
//if self.inLiveResize { return }
DispatchUtils.gui {
let curPos = self.grid.putPosition
// NSLog("\(#function): \(curPos) -> \(string)")
@ -104,6 +113,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
}
public func putMarkedText(markedText: String) {
//if self.inLiveResize { return }
DispatchUtils.gui {
NSLog("\(#function): '\(markedText)'")
let curPos = self.grid.putPosition
@ -118,6 +128,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
}
public func unmarkRow(row: Int32, column: Int32) {
//if self.inLiveResize { return }
DispatchUtils.gui {
let position = Position(row: Int(row), column: Int(column))
@ -140,15 +151,18 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
}
public func flush() {
// Swift.print("\(self.grid)")
}
public func updateForeground(fg: Int32) {
//if self.inLiveResize { return }
DispatchUtils.gui {
self.grid.foreground = UInt32(bitPattern: fg)
}
}
public func updateBackground(bg: Int32) {
//if self.inLiveResize { return }
DispatchUtils.gui {
self.grid.background = UInt32(bitPattern: bg)
self.layer?.backgroundColor = ColorUtils.colorIgnoringAlpha(self.grid.background).CGColor
@ -156,6 +170,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
}
public func updateSpecial(sp: Int32) {
//if self.inLiveResize { return }
DispatchUtils.gui {
self.grid.special = UInt32(bitPattern: sp)
}

View File

@ -4,6 +4,7 @@
*/
import Cocoa
import PureLayout
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, NeoVimViewDelegate {
@ -24,9 +25,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, NeoVimViewDelegate {
self.neoVim = NeoVim()
self.neoVim.view.delegate = self
self.neoVim.view.setFrameSize(CGSize(width: 100.0, height: 100.0))
self.neoVim.view.setFrameOrigin(CGPoint(x: 0, y: 0))
let view = self.neoVim.view
view.translatesAutoresizingMaskIntoConstraints = false
self.window.contentView?.addSubview(self.neoVim.view)
view.autoPinEdgesToSuperviewEdges()
self.window.makeFirstResponder(self.neoVim.view)
@ -42,9 +44,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, NeoVimViewDelegate {
}
func resizeToSize(size: CGSize) {
let delta = CGFloat(4 + 4)
let bigger = CGSize(width: size.width + delta, height: size.height + delta)
self.neoVim.view.setFrameSize(bigger)
// let delta = CGFloat(4 + 4)
// let bigger = CGSize(width: size.width + delta, height: size.height + delta)
// self.neoVim.view.setFrameSize(bigger)
// NSLog("\(#function)")
}
func setTitle(title: String) {