diff --git a/NeoVimXpc/NeoVimXpcImpl.m b/NeoVimXpc/NeoVimXpcImpl.m index a7744c10..4193d8f6 100644 --- a/NeoVimXpc/NeoVimXpcImpl.m +++ b/NeoVimXpc/NeoVimXpcImpl.m @@ -18,6 +18,7 @@ #import #import +#define pun_type(t, x) (*((t *)(&x))) // We declare nvim_main because it's not declared in any header files of neovim extern int nvim_main(int argc, char **argv); @@ -32,6 +33,10 @@ static uv_cond_t condition; static id neo_vim_osx_ui; +static unsigned int default_foreground = qDefaultForeground; +static unsigned int default_background = qDefaultBackground; +static unsigned int default_special = qDefaultSpecial; + typedef struct { UIBridgeData *bridge; Loop *loop; @@ -182,12 +187,12 @@ static void xpc_ui_highlight_set(UI *ui __unused, HlAttrs attrs) { CellAttributes cellAttrs; cellAttrs.fontTrait = trait; - unsigned int fg = attrs.foreground == -1 ? qDefaultForeground : *((unsigned int*)(&attrs.foreground)); - unsigned int bg = attrs.background == -1 ? qDefaultBackground : *((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 ? qDefaultSpecial : *((unsigned int*)(&attrs.special)); + cellAttrs.special = attrs.special == -1 ? default_special : pun_type(unsigned int, attrs.special); [neo_vim_osx_ui highlightSet:cellAttrs]; } @@ -215,17 +220,26 @@ static void xpc_ui_flush(UI *ui __unused) { } static void xpc_ui_update_fg(UI *ui __unused, int fg) { - //printf("update fg\n"); +// printf("update fg: %x\n", fg); + if (fg != -1) { + default_foreground = pun_type(unsigned int, fg); + } [neo_vim_osx_ui updateForeground:fg]; } static void xpc_ui_update_bg(UI *ui __unused, int bg) { - //printf("update bg\n"); +// printf("update bg: %x\n", bg); + if (bg != -1) { + default_background = pun_type(unsigned int, bg); + } [neo_vim_osx_ui updateBackground:bg]; } static void xpc_ui_update_sp(UI *ui __unused, int sp) { - //printf("update sp\n"); +// printf("update sp: %x\n", sp); + if (sp != -1) { + default_special = pun_type(unsigned int, sp); + } [neo_vim_osx_ui updateSpecial:sp]; } @@ -365,7 +379,7 @@ static void wait_input_enqueue(void **argv) { } - (void)vimInput:(NSString *)input { - // we retain, but not release here since it will be released in wait_input_enqueue + // We retain, but not release here since it will be released in wait_input_enqueue. loop_schedule(&main_loop, event_create(1, wait_input_enqueue, 1, [input retain])); } diff --git a/SwiftNeoVim/Grid.swift b/SwiftNeoVim/Grid.swift index efdae7d2..7db1cfc3 100644 --- a/SwiftNeoVim/Grid.swift +++ b/SwiftNeoVim/Grid.swift @@ -96,7 +96,10 @@ class Grid: CustomStringConvertible { self.size = size self.position = Position.zero - let emptyRow = Array(count: size.width, repeatedValue: Cell(string: " ", attrs: qEmptyCellAttributes)) + let emptyCellAttrs = CellAttributes(fontTrait: .None, + foreground: self.foreground, background: self.background, special: self.special) + + let emptyRow = Array(count: size.width, repeatedValue: Cell(string: " ", attrs: emptyCellAttrs)) self.cells = Array(count: size.height, repeatedValue: emptyRow) } @@ -167,4 +170,4 @@ class Grid: CustomStringConvertible { self.cells[i].replaceRange(region.left...region.right, with: clearedRow) } } -} \ No newline at end of file +} diff --git a/SwiftNeoVim/MMCoreTextView.h b/SwiftNeoVim/MMCoreTextView.h index 22ae6be7..444b88c3 100644 --- a/SwiftNeoVim/MMCoreTextView.h +++ b/SwiftNeoVim/MMCoreTextView.h @@ -1,9 +1,11 @@ @import Cocoa; @import CoreText; -CTFontRef lookupFont(NSMutableArray *fontCache, const unichar *chars, UniCharCount count, CTFontRef currFontRef); -CFAttributedStringRef attributedStringForString(NSString *string, const CTFontRef font, BOOL useLigatures); -UniCharCount fetchGlyphsAndAdvances(const CTLineRef line, CGGlyph *glyphs, CGSize *advances, UniCharCount length); -UniCharCount gatherGlyphs(CGGlyph glyphs[], UniCharCount count); -UniCharCount ligatureGlyphsForChars(const unichar *chars, CGGlyph *glyphs, CGPoint *positions, UniCharCount length, CTFontRef font); -void recurseDraw(const unichar *chars, CGGlyph *glyphs, CGPoint *positions, UniCharCount length, CGContextRef context, CTFontRef fontRef, NSMutableArray *fontCache, BOOL useLigatures); +void recurseDraw( + const unichar *chars, + CGGlyph *glyphs, CGPoint *positions, UniCharCount length, + CGContextRef context, + CTFontRef fontRef, + NSMutableArray *fontCache, + BOOL useLigatures +); diff --git a/SwiftNeoVim/MMCoreTextView.m b/SwiftNeoVim/MMCoreTextView.m index 8cc29c0a..3e810b01 100644 --- a/SwiftNeoVim/MMCoreTextView.m +++ b/SwiftNeoVim/MMCoreTextView.m @@ -16,7 +16,7 @@ #import "MMCoreTextView.h" - CTFontRef + static CTFontRef lookupFont(NSMutableArray *fontCache, const unichar *chars, UniCharCount count, CTFontRef currFontRef) { @@ -48,7 +48,7 @@ lookupFont(NSMutableArray *fontCache, const unichar *chars, UniCharCount count, return newFontRef; } - CFAttributedStringRef + static CFAttributedStringRef attributedStringForString(NSString *string, const CTFontRef font, BOOL useLigatures) { @@ -66,7 +66,7 @@ attributedStringForString(NSString *string, const CTFontRef font, (CFDictionaryRef)attrs); } - UniCharCount + static UniCharCount fetchGlyphsAndAdvances(const CTLineRef line, CGGlyph *glyphs, CGSize *advances, UniCharCount length) { @@ -96,7 +96,7 @@ fetchGlyphsAndAdvances(const CTLineRef line, CGGlyph *glyphs, CGSize *advances, return offset; } - UniCharCount + static UniCharCount gatherGlyphs(CGGlyph glyphs[], UniCharCount count) { // Gather scattered glyphs that was happended by Surrogate pair chars @@ -112,7 +112,7 @@ gatherGlyphs(CGGlyph glyphs[], UniCharCount count) return glyphCount; } - UniCharCount + static UniCharCount ligatureGlyphsForChars(const unichar *chars, CGGlyph *glyphs, CGPoint *positions, UniCharCount length, CTFontRef font) { diff --git a/SwiftNeoVim/NeoVimUiBridgeProtocol.h b/SwiftNeoVim/NeoVimUiBridgeProtocol.h index fd1a125a..be353032 100644 --- a/SwiftNeoVim/NeoVimUiBridgeProtocol.h +++ b/SwiftNeoVim/NeoVimUiBridgeProtocol.h @@ -76,15 +76,18 @@ typedef struct { - (void)flush; /** - * Set the foreground color. + * Set the default foreground color. */ - (void)updateForeground:(int)fg; /** - * Set the background color. + * Set the default background color. */ - (void)updateBackground:(int)bg; +/** + * Set the default special color, eg curly underline for spelling errors. + */ - (void)updateSpecial:(int)sp; - (void)suspend; - (void)setTitle:(NSString *)title; diff --git a/SwiftNeoVim/NeoVimView.swift b/SwiftNeoVim/NeoVimView.swift index 19f98f3d..f0283ea0 100644 --- a/SwiftNeoVim/NeoVimView.swift +++ b/SwiftNeoVim/NeoVimView.swift @@ -19,24 +19,22 @@ func != (left: CellAttributes, right: CellAttributes) -> Bool { return !(left == right) } -private struct RowFragment: CustomStringConvertible { - - let row: Int - let range: Range - - var description: String { - return "RowFragment<\(row): \(range)>" +extension CellAttributes: CustomStringConvertible { + + public var description: String { + return "CellAttributes let attrs: CellAttributes var description: String { - return "AttributedRowFragment<\(row): \(range)\n\(attrs)>" + return "RowRun<\(row): \(range)\n\(attrs)>" } } @@ -85,7 +83,7 @@ public class NeoVimView: NSView { guard self.grid.hasData else { return } - + let context = NSGraphicsContext.currentContext()!.CGContext CGContextSetTextMatrix(context, CGAffineTransformIdentity); @@ -93,7 +91,7 @@ public class NeoVimView: NSView { let dirtyRects = self.rectsBeingDrawn() - self.attributedRowFragmentsIntersecting(rects: dirtyRects).forEach { rowFrag in + self.rowRunIntersecting(rects: dirtyRects).forEach { rowFrag in 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 } @@ -119,32 +117,7 @@ public class NeoVimView: NSView { backgroundRect.fill() } - private func attributedRowFragmentsIntersecting(rects rects: [CGRect]) -> [AttributedRowFragment] { - return self.rowFragmentsIntersecting(rects: rects) - .map { rowFrag -> [AttributedRowFragment] in - let row = rowFrag.row - let rowCells = self.grid.cells[rowFrag.row] - let range = rowFrag.range - let startIndex = range.startIndex - - var result = [ - AttributedRowFragment(row: row, range: startIndex...startIndex, attrs: rowCells[startIndex].attrs) - ] - range.forEach { idx in - if rowCells[idx].attrs == result.last!.attrs { - let last = result.popLast()! - result.append(AttributedRowFragment(row: row, range: last.range.startIndex...idx, attrs: last.attrs)) - } else { - result.append(AttributedRowFragment(row: row, range: idx...idx, attrs: rowCells[idx].attrs)) - } - } - - return result - } - .flatMap { $0 } - } - - private func rowFragmentsIntersecting(rects rects: [CGRect]) -> [RowFragment] { + private func rowRunIntersecting(rects rects: [CGRect]) -> [RowRun] { return rects .map { rect -> Region in let rowStart = Int(floor((self.frame.height - (rect.origin.y + rect.size.height)) / self.cellSize.height)) @@ -153,10 +126,30 @@ public class NeoVimView: NSView { let columnEnd = Int(ceil((rect.origin.x + rect.size.width) / self.cellSize.width)) - 1 return Region(top: rowStart, bottom: rowEnd, left: columnStart, right: columnEnd) } // There can be overlaps between the Regions, but for the time being we ignore them. - .map { region -> [RowFragment] in - return (region.rowRange).map { RowFragment(row: $0, range: region.columnRange) } - } - .flatMap { $0 } + .map { region -> [RowRun] in + return (region.rowRange) + .map { row -> [RowRun] in + let range = region.columnRange + let rowCells = self.grid.cells[row] + let startIndex = range.startIndex + + var result = [ + RowRun(row: row, range: startIndex...startIndex, attrs: rowCells[startIndex].attrs) + ] + range.forEach { idx in + if rowCells[idx].attrs == result.last!.attrs { + let last = result.popLast()! + result.append(RowRun(row: row, range: last.range.startIndex...idx, attrs: last.attrs)) + } else { + result.append(RowRun(row: row, range: idx...idx, attrs: rowCells[idx].attrs)) + } + } + + return result + } // -> [[RowRun]] + .flatMap { $0 } // -> [RowRun] + } // -> [[RowRun]] + .flatMap { $0 } // -> [RowRun] } private func positionOnView(row: Int, column: Int) -> CGPoint { @@ -255,20 +248,19 @@ extension NeoVimView: NeoVimUiBridgeProtocol { Swift.print("### scroll count: \(count)") gui { -// Swift.print("before scroll: \(self.grid)") self.grid.scroll(Int(count)) -// Swift.print("after scroll: \(self.grid)") - let top = CGFloat(self.grid.region.top) - let bottom = CGFloat(self.grid.region.bottom) - let left = CGFloat(self.grid.region.left) - let right = CGFloat(self.grid.region.right) + let region = self.grid.region + let top = CGFloat(region.top) + let bottom = CGFloat(region.bottom) + let left = CGFloat(region.left) + let right = CGFloat(region.right) let width = right - left + 1 let height = bottom - top + 1 let rect = CGRect(x: left * self.cellSize.width, y: bottom * self.cellSize.height, - width: width * self.cellSize.width, height: height * self.cellSize.height) + width: width * self.cellSize.width, height: height * self.cellSize.height) self.setNeedsDisplayInRect(rect) } } @@ -309,15 +301,24 @@ extension NeoVimView: NeoVimUiBridgeProtocol { } public func updateForeground(fg: Int32) { - // Swift.print("### update fg: \(colorFromCode(fg))") +// Swift.print("### update fg: \(String(format: "%x", fg))") + gui { + self.grid.foreground = UInt32(bitPattern: fg) + } } public func updateBackground(bg: Int32) { - // Swift.print("### update bg: \(colorFromCode(bg, kind: .Background))") +// Swift.print("### update bg: \(String(format: "%x", bg))") + gui { + self.grid.background = UInt32(bitPattern: bg) + } } public func updateSpecial(sp: Int32) { - // Swift.print("### update sp: \(colorFromCode(sp, kind: .Special))") +// Swift.print("### update sp: \(String(format: "%x", sp)") + gui { + self.grid.special = UInt32(bitPattern: sp) + } } public func suspend() {