mirror of
https://github.com/qvacua/vimr.git
synced 2024-12-25 14:52:19 +03:00
Merge remote-tracking branch 'origin/develop' into update-neovim
This commit is contained in:
commit
bc45c2be12
@ -17,9 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>SNAPSHOT-300</string>
|
||||
<string>SNAPSHOT-301</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>300</string>
|
||||
<string>301</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
@ -68,6 +68,9 @@ static CFDataRef local_server_callback(CFMessagePortRef local, SInt32 msgid, CFD
|
||||
case NvimBridgeMsgIdFocusGained:
|
||||
return data_async(data, neovim_focus_gained);
|
||||
|
||||
case NvimBridgeMsgIdReadyForRpcEvents:
|
||||
return data_async(data, neovim_ready_for_rpcevents);
|
||||
|
||||
default:
|
||||
CFRelease(data);
|
||||
return NULL;
|
||||
|
@ -19,5 +19,6 @@ extern void neovim_vim_input(void **argv);
|
||||
extern void neovim_delete_and_input(void **argv);
|
||||
|
||||
extern void neovim_focus_gained(void **argv);
|
||||
extern void neovim_ready_for_rpcevents(void **argv);
|
||||
|
||||
extern void neovim_debug1(void **argv);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#define FileInfo CarbonFileInfo
|
||||
#define Boolean CarbonBoolean
|
||||
|
||||
#import <nvim/main.h>
|
||||
#import <nvim/vim.h>
|
||||
#import <nvim/api/vim.h>
|
||||
#import <nvim/ui.h>
|
||||
@ -73,6 +74,8 @@ static NSInteger _initialHeight = 15;
|
||||
static msgpack_sbuffer flush_sbuffer;
|
||||
static msgpack_packer *flush_packer;
|
||||
|
||||
static dispatch_queue_t rpc_queue;
|
||||
|
||||
#pragma mark Helper functions
|
||||
|
||||
static inline String vim_string_from(NSString *str) {
|
||||
@ -245,6 +248,8 @@ static void server_ui_main(UIBridgeData *bridge, UI *ui) {
|
||||
msgpack_sbuffer_init(&flush_sbuffer);
|
||||
flush_packer = msgpack_packer_new(&flush_sbuffer, msgpack_sbuffer_write);
|
||||
|
||||
rpc_queue = dispatch_queue_create("rpc_queu", NULL);
|
||||
|
||||
Loop loop;
|
||||
loop_init(&loop, NULL);
|
||||
|
||||
@ -553,6 +558,13 @@ void custom_ui_start(void) {
|
||||
ui_bridge_attach(ui, server_ui_main, server_ui_scheduler);
|
||||
}
|
||||
|
||||
void custom_ui_rpcevent_subscribed() {
|
||||
dispatch_async(rpc_queue, ^{
|
||||
[_neovim_server sendMessageWithId:NvimServerMsgIdRpcEventSubscribed
|
||||
data:NULL];
|
||||
});
|
||||
}
|
||||
|
||||
void custom_ui_autocmds_groups(
|
||||
event_T event,
|
||||
char_u *fname __unused,
|
||||
@ -573,6 +585,8 @@ void custom_ui_autocmds_groups(
|
||||
case EVENT_TABENTER:
|
||||
case EVENT_TEXTCHANGED:
|
||||
case EVENT_TEXTCHANGEDI:
|
||||
case EVENT_VIMENTER:
|
||||
case EVENT_GUIENTER:
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -739,6 +753,25 @@ void neovim_delete_and_input(void **argv) {
|
||||
});
|
||||
}
|
||||
|
||||
static void do_autocmd_guienter() {
|
||||
static bool recursive = false;
|
||||
|
||||
if (recursive) {
|
||||
return; // disallow recursion
|
||||
}
|
||||
recursive = true;
|
||||
apply_autocmds(EVENT_GUIENTER, NULL, NULL, false, curbuf);
|
||||
recursive = false;
|
||||
}
|
||||
|
||||
static void guienter_event(void **argv __unused) {
|
||||
do_autocmd_guienter();
|
||||
}
|
||||
|
||||
static void aucmd_schedule_guienter() {
|
||||
loop_schedule_deferred(&main_loop, event_create(guienter_event, 0));
|
||||
}
|
||||
|
||||
void neovim_focus_gained(void **argv) {
|
||||
work_async(argv, ^(NSData *data) {
|
||||
const bool *values = data.bytes;
|
||||
@ -747,6 +780,12 @@ void neovim_focus_gained(void **argv) {
|
||||
});
|
||||
}
|
||||
|
||||
void neovim_ready_for_rpcevents(void **argv) {
|
||||
work_async(argv, ^(NSData *data) {
|
||||
aucmd_schedule_guienter();
|
||||
});
|
||||
}
|
||||
|
||||
void neovim_debug1(void **argv) {
|
||||
work_async(argv, ^(NSData *data) {
|
||||
NSLog(@"normal fg: %#08X", normal_fg);
|
||||
|
@ -45,7 +45,7 @@
|
||||
4B177886201220F300E32FF0 /* SharedTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 1929B4F32708E99C40A57020 /* SharedTypes.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
4B17E549209E3E4100265C1D /* RxNeovimApi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B17E548209E3E4100265C1D /* RxNeovimApi.framework */; };
|
||||
4B21ED53213D4AEC009FD017 /* CocoaCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B0C89838D8402BB80BFC /* CocoaCommons.swift */; };
|
||||
4B8662E81FDC3F9F007F490D /* vimr.vim in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B8662E41FDC3D4F007F490D /* vimr.vim */; };
|
||||
4B8662E81FDC3F9F007F490D /* com.qvacua.NvimView.vim in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B8662E41FDC3D4F007F490D /* com.qvacua.NvimView.vim */; };
|
||||
4B90F02E1FD2AFAE008A39E0 /* NvimView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0101FD2AFAC008A39E0 /* NvimView.swift */; };
|
||||
4B90F02F1FD2AFAE008A39E0 /* NvimView+Resize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0111FD2AFAC008A39E0 /* NvimView+Resize.swift */; };
|
||||
4B90F0301FD2AFAE008A39E0 /* KeyUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0121FD2AFAC008A39E0 /* KeyUtils.swift */; };
|
||||
@ -140,7 +140,7 @@
|
||||
dstPath = runtime/plugin;
|
||||
dstSubfolderSpec = 7;
|
||||
files = (
|
||||
4B8662E81FDC3F9F007F490D /* vimr.vim in CopyFiles */,
|
||||
4B8662E81FDC3F9F007F490D /* com.qvacua.NvimView.vim in CopyFiles */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -199,7 +199,7 @@
|
||||
4B0A1B152129F49500F1E02F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
4B0A1B38212B332800F1E02F /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = ../Carthage/Build/Mac/Nimble.framework; sourceTree = "<group>"; };
|
||||
4B17E548209E3E4100265C1D /* RxNeovimApi.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxNeovimApi.framework; path = ../Carthage/Build/Mac/RxNeovimApi.framework; sourceTree = "<group>"; };
|
||||
4B8662E41FDC3D4F007F490D /* vimr.vim */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = vimr.vim; sourceTree = "<group>"; };
|
||||
4B8662E41FDC3D4F007F490D /* com.qvacua.NvimView.vim */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.vim; path = com.qvacua.NvimView.vim; sourceTree = "<group>"; };
|
||||
4B90F0041FD2AF59008A39E0 /* NvimView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NvimView.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4B90F0081FD2AF59008A39E0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
4B90F0101FD2AFAC008A39E0 /* NvimView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NvimView.swift; sourceTree = "<group>"; };
|
||||
@ -359,7 +359,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B90F0081FD2AF59008A39E0 /* Info.plist */,
|
||||
4B8662E41FDC3D4F007F490D /* vimr.vim */,
|
||||
4B8662E41FDC3D4F007F490D /* com.qvacua.NvimView.vim */,
|
||||
4BF18C5C1FD2EEE400DF95D1 /* NvimView.h */,
|
||||
4B90F0121FD2AFAC008A39E0 /* KeyUtils.swift */,
|
||||
4B90F0271FD2AFAD008A39E0 /* Logger.swift */,
|
||||
@ -783,7 +783,7 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 300;
|
||||
CURRENT_PROJECT_VERSION = 301;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@ -845,7 +845,7 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 300;
|
||||
CURRENT_PROJECT_VERSION = 301;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@ -874,7 +874,7 @@
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 300;
|
||||
DYLIB_CURRENT_VERSION = 301;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac";
|
||||
FRAMEWORK_VERSION = A;
|
||||
@ -896,7 +896,7 @@
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 300;
|
||||
DYLIB_CURRENT_VERSION = 301;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac";
|
||||
FRAMEWORK_VERSION = A;
|
||||
|
@ -15,9 +15,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>SNAPSHOT-300</string>
|
||||
<string>SNAPSHOT-301</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>300</string>
|
||||
<string>301</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2017 Tae Won Ha. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
@ -86,7 +86,7 @@ class Logger {
|
||||
default: self.name = String(describing: name)
|
||||
}
|
||||
|
||||
self.logDateFormatter.dateFormat = "dd HH:mm:SSS"
|
||||
self.logDateFormatter.dateFormat = "dd HH:mm:ss.SSS"
|
||||
self.appender = appender
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,13 @@ extension NvimView {
|
||||
}
|
||||
|
||||
let cursorRegion = self.cursorRegion(for: self.ugrid.cursorPosition)
|
||||
if cursorRegion.top < 0
|
||||
|| cursorRegion.bottom > self.ugrid.size.height - 1
|
||||
|| cursorRegion.left < 0
|
||||
|| cursorRegion.right > self.ugrid.size.width - 1 {
|
||||
logger.error("\(cursorRegion) vs. \(self.ugrid.size)")
|
||||
return
|
||||
}
|
||||
guard let cursorAttrs = self.cellAttributesCollection.attributes(
|
||||
of: self.ugrid.cells[cursorPosition.row][cursorPosition.column].attrId
|
||||
)?.reversed else {
|
||||
|
@ -52,8 +52,12 @@ extension NvimView {
|
||||
return
|
||||
}
|
||||
|
||||
self.offset.x = floor((size.width - self.cellSize.width * CGFloat(discreteSize.width)) / 2)
|
||||
self.offset.y = floor((size.height - self.cellSize.height * CGFloat(discreteSize.height)) / 2)
|
||||
self.offset.x = floor(
|
||||
(size.width - self.cellSize.width * CGFloat(discreteSize.width)) / 2
|
||||
)
|
||||
self.offset.y = floor(
|
||||
(size.height - self.cellSize.height * CGFloat(discreteSize.height)) / 2
|
||||
)
|
||||
|
||||
self.bridge
|
||||
.resize(width: discreteSize.width, height: discreteSize.height)
|
||||
@ -62,32 +66,50 @@ extension NvimView {
|
||||
|
||||
private func launchNeoVim(_ size: Size) {
|
||||
logger.info("=== Starting neovim...")
|
||||
let sockPath = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("vimr_\(self.uuid).sock").path
|
||||
let sockPath = URL(
|
||||
fileURLWithPath: NSTemporaryDirectory()
|
||||
).appendingPathComponent("vimr_\(self.uuid).sock").path
|
||||
|
||||
self.api.msgpackRawStream
|
||||
.subscribe(onNext: { msg in
|
||||
switch msg {
|
||||
case let .notification(method, params):
|
||||
print("NOTIFICATION: \(method) with \(params.count) elements")
|
||||
case let .error(_, msg):
|
||||
print("MSG ERROR: \(msg)")
|
||||
default:
|
||||
print("???")
|
||||
break
|
||||
}
|
||||
}, onError: { print("ERROR: \($0)" )})
|
||||
.disposed(by: self.disposeBag)
|
||||
.subscribe(onNext: { msg in
|
||||
switch msg {
|
||||
|
||||
// We wait here, since the user of NvimView cannot subscribe on the Completable. We could demand that the user
|
||||
// call launchNeoVim() by themselves, but...
|
||||
case let .notification(method, params):
|
||||
logger.debug("NOTIFICATION: \(method): \(params)")
|
||||
|
||||
guard method == NvimView.rpcEventName else { return }
|
||||
self.eventsSubject.onNext(.rpcEvent(method, params))
|
||||
|
||||
case let .error(_, msg):
|
||||
logger.debug("MSG ERROR: \(msg)")
|
||||
|
||||
default:
|
||||
logger.debug("???: This should not happen")
|
||||
break
|
||||
|
||||
}
|
||||
}, onError: { print("ERROR: \($0)") })
|
||||
.disposed(by: self.disposeBag)
|
||||
|
||||
// We wait here, since the user of NvimView cannot subscribe
|
||||
// on the Completable. We could demand that the user call launchNeoVim()
|
||||
// by themselves, but...
|
||||
try? self.bridge
|
||||
.runLocalServerAndNvim(width: size.width, height: size.height)
|
||||
.andThen(self.api.run(at: sockPath))
|
||||
.andThen(
|
||||
self.sourceFileUrls.reduce(Completable.empty()) { prev, url in
|
||||
prev.andThen(self.api
|
||||
.commandOutput(str: "source \(url.path)")
|
||||
.asCompletable())
|
||||
}
|
||||
)
|
||||
.andThen(self.api.subscribe(event: NvimView.rpcEventName))
|
||||
.wait()
|
||||
}
|
||||
|
||||
private func randomEmoji() -> String {
|
||||
let idx = Int(arc4random_uniform(UInt32(emojis.count)))
|
||||
let idx = Int.random(in: 0..<emojis.count)
|
||||
guard let scalar = UnicodeScalar(emojis[idx]) else {
|
||||
return "😎"
|
||||
}
|
||||
|
@ -119,7 +119,6 @@ extension NvimView {
|
||||
self.bridgeLogger.hr()
|
||||
try? self.api
|
||||
.stop()
|
||||
.andThen(self.bridge.quit())
|
||||
.andThen(Completable.create { completable in
|
||||
self.eventsSubject.onNext(.neoVimStopped)
|
||||
self.eventsSubject.onCompleted()
|
||||
@ -127,6 +126,7 @@ extension NvimView {
|
||||
completable(.completed)
|
||||
return Disposables.create()
|
||||
})
|
||||
.andThen(self.bridge.quit())
|
||||
.observeOn(MainScheduler.instance)
|
||||
.wait()
|
||||
}
|
||||
@ -141,6 +141,44 @@ extension NvimView {
|
||||
}
|
||||
let bufferHandle = array[1]
|
||||
|
||||
if event == .vimenter {
|
||||
Completable
|
||||
.empty()
|
||||
.observeOn(SerialDispatchQueueScheduler(qos: .userInitiated))
|
||||
.andThen(
|
||||
Completable.create { completable in
|
||||
self.rpcEventSubscribedCondition.lock()
|
||||
defer { self.rpcEventSubscribedCondition.unlock() }
|
||||
|
||||
while !self.rpcEventSubscribedFlag
|
||||
&& self.rpcEventSubscribedCondition
|
||||
.wait(until: Date(timeIntervalSinceNow: 5)) {}
|
||||
|
||||
completable(.completed)
|
||||
return Disposables.create()
|
||||
}
|
||||
)
|
||||
.andThen(
|
||||
{
|
||||
let ginitPath = URL(fileURLWithPath: NSHomeDirectory())
|
||||
.appendingPathComponent(".config/nvim/ginit.vim").path
|
||||
let loadGinit = FileManager.default.fileExists(atPath: ginitPath)
|
||||
if loadGinit {
|
||||
return self.api.command(command: "source \(ginitPath)")
|
||||
} else {
|
||||
return .empty()
|
||||
}
|
||||
}()
|
||||
)
|
||||
.andThen(self.bridge.notifyReadinessForRpcEvents())
|
||||
.subscribe(onCompleted: {
|
||||
logger.debug("GUIEnter aucmd fired")
|
||||
})
|
||||
.disposed(by: self.disposeBag)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
#if TRACE
|
||||
self.bridgeLogger.trace("\(event) -> \(bufferHandle)")
|
||||
#endif
|
||||
@ -200,8 +238,8 @@ extension NvimView {
|
||||
#if TRACE
|
||||
self.bridgeLogger.trace(
|
||||
"row: \(row), startCol: \(startCol), endCol: \(endCol), " +
|
||||
"clearCol: \(clearCol), clearAttr: \(clearAttr), " +
|
||||
"chunk: \(chunk), attrIds: \(attrIds)"
|
||||
"clearCol: \(clearCol), clearAttr: \(clearAttr), " +
|
||||
"chunk: \(chunk), attrIds: \(attrIds)"
|
||||
)
|
||||
#endif
|
||||
|
||||
@ -242,13 +280,13 @@ extension NvimView {
|
||||
}
|
||||
|
||||
if row == self.markedPosition.row
|
||||
&& startCol <= self.markedPosition.column
|
||||
&& self.markedPosition.column <= endCol {
|
||||
&& startCol <= self.markedPosition.column
|
||||
&& self.markedPosition.column <= endCol {
|
||||
self.ugrid.markCell(at: self.markedPosition)
|
||||
}
|
||||
|
||||
let oldRowContainsWideChar = self.ugrid.cells[row][startCol..<endCol]
|
||||
.first(where: { $0.string.isEmpty }) != nil
|
||||
.first(where: { $0.string.isEmpty }) != nil
|
||||
let newRowContainsWideChar = chunk.first(where: { $0.isEmpty }) != nil
|
||||
|
||||
if !oldRowContainsWideChar && !newRowContainsWideChar {
|
||||
@ -364,6 +402,15 @@ extension NvimView {
|
||||
self.eventsSubject.onNext(.setDirtyStatus(dirty))
|
||||
}
|
||||
|
||||
final func rpcEventSubscribed() {
|
||||
self.rpcEventSubscribedCondition.lock()
|
||||
defer { self.rpcEventSubscribedCondition.unlock() }
|
||||
self.rpcEventSubscribedFlag = true
|
||||
self.rpcEventSubscribedCondition.broadcast()
|
||||
|
||||
self.eventsSubject.onNext(.rpcEventSubscribed)
|
||||
}
|
||||
|
||||
final func setAttr(with value: MessagePackValue) {
|
||||
guard let array = value.arrayValue else { return }
|
||||
guard array.count == 6 else { return }
|
||||
@ -377,7 +424,7 @@ extension NvimView {
|
||||
else {
|
||||
|
||||
self.bridgeLogger.error("Could not get highlight attributes from " +
|
||||
"\(value)")
|
||||
"\(value)")
|
||||
return
|
||||
}
|
||||
let trait = FontTrait(rawValue: UInt(rawTrait))
|
||||
|
@ -6,10 +6,11 @@
|
||||
import Cocoa
|
||||
import RxNeovimApi
|
||||
import RxSwift
|
||||
import MessagePack
|
||||
|
||||
public class NvimView: NSView,
|
||||
NSUserInterfaceValidations,
|
||||
NSTextInputClient {
|
||||
NSUserInterfaceValidations,
|
||||
NSTextInputClient {
|
||||
|
||||
// MARK: - Public
|
||||
public struct Config {
|
||||
@ -18,16 +19,20 @@ public class NvimView: NSView,
|
||||
var cwd: URL
|
||||
var nvimArgs: [String]?
|
||||
var envDict: [String: String]?
|
||||
var sourceFiles: [URL]
|
||||
|
||||
public init(useInteractiveZsh: Bool,
|
||||
cwd: URL,
|
||||
nvimArgs: [String]?,
|
||||
envDict: [String: String]?) {
|
||||
|
||||
public init(
|
||||
useInteractiveZsh: Bool,
|
||||
cwd: URL,
|
||||
nvimArgs: [String]?,
|
||||
envDict: [String: String]?,
|
||||
sourceFiles: [URL]
|
||||
) {
|
||||
self.useInteractiveZsh = useInteractiveZsh
|
||||
self.cwd = cwd
|
||||
self.nvimArgs = nvimArgs
|
||||
self.envDict = envDict
|
||||
self.sourceFiles = sourceFiles
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,6 +55,9 @@ public class NvimView: NSView,
|
||||
case scroll
|
||||
case cursor(Position)
|
||||
|
||||
case rpcEvent(String, [MessagePack.MessagePackValue])
|
||||
case rpcEventSubscribed
|
||||
|
||||
case initVimError
|
||||
|
||||
// FIXME: maybe do onError()?
|
||||
@ -95,12 +103,14 @@ public class NvimView: NSView,
|
||||
|
||||
public var description: String {
|
||||
return "NVV.Theme<" +
|
||||
"fg: \(self.foreground.hex), bg: \(self.background.hex), " +
|
||||
"visual-fg: \(self.visualForeground.hex), visual-bg: \(self.visualBackground.hex)" +
|
||||
">"
|
||||
"fg: \(self.foreground.hex), bg: \(self.background.hex), " +
|
||||
"visual-fg: \(self.visualForeground.hex), visual-bg: \(self.visualBackground.hex)" +
|
||||
">"
|
||||
}
|
||||
}
|
||||
|
||||
public static let rpcEventName = "com.qvacua.NvimView"
|
||||
|
||||
public static let minFontSize = CGFloat(4)
|
||||
public static let maxFontSize = CGFloat(128)
|
||||
public static let defaultFont = NSFont.userFixedPitchFont(ofSize: 12)!
|
||||
@ -112,7 +122,7 @@ public class NvimView: NSView,
|
||||
public var isLeftOptionMeta = false
|
||||
public var isRightOptionMeta = false
|
||||
|
||||
public let uuid = UUID().uuidString
|
||||
public let uuid = UUID()
|
||||
|
||||
public internal(set) var mode = CursorModeShape.normal
|
||||
|
||||
@ -202,6 +212,8 @@ public class NvimView: NSView,
|
||||
self.scheduler = SerialDispatchQueueScheduler(queue: self.queue,
|
||||
internalSerialQueueName: "com.qvacua.NvimView.NvimView")
|
||||
|
||||
self.sourceFileUrls = config.sourceFiles
|
||||
|
||||
super.init(frame: .zero)
|
||||
self.registerForDraggedTypes([NSPasteboard.PasteboardType(String(kUTTypeFileURL))])
|
||||
|
||||
@ -285,6 +297,10 @@ public class NvimView: NSView,
|
||||
case let .highlightAttrs(value):
|
||||
self.setAttr(with: value)
|
||||
|
||||
case .rpcEventSubscribed:
|
||||
self.rpcEventSubscribed()
|
||||
|
||||
|
||||
case .debug1:
|
||||
self.debug1(self)
|
||||
|
||||
@ -296,10 +312,16 @@ public class NvimView: NSView,
|
||||
}
|
||||
|
||||
convenience override public init(frame rect: NSRect) {
|
||||
self.init(frame: rect, config: Config(useInteractiveZsh: false,
|
||||
cwd: URL(fileURLWithPath: NSHomeDirectory()),
|
||||
nvimArgs: nil,
|
||||
envDict: nil))
|
||||
self.init(
|
||||
frame: rect,
|
||||
config: Config(
|
||||
useInteractiveZsh: false,
|
||||
cwd: URL(fileURLWithPath: NSHomeDirectory()),
|
||||
nvimArgs: nil,
|
||||
envDict: nil,
|
||||
sourceFiles: []
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
@ -364,6 +386,11 @@ public class NvimView: NSView,
|
||||
shouldLogDebug: nil
|
||||
)
|
||||
|
||||
let sourceFileUrls: [URL]
|
||||
|
||||
let rpcEventSubscribedCondition = NSCondition()
|
||||
var rpcEventSubscribedFlag = false
|
||||
|
||||
// MARK: - Private
|
||||
private var _linespacing = NvimView.defaultLinespacing
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ class UiBridge {
|
||||
case defaultColorsChanged(MessagePackValue)
|
||||
case autoCommandEvent(MessagePackValue)
|
||||
case highlightAttrs(MessagePackValue)
|
||||
case rpcEventSubscribed
|
||||
case debug1
|
||||
case unknown
|
||||
}
|
||||
@ -51,7 +52,7 @@ class UiBridge {
|
||||
return self.streamSubject.asObservable()
|
||||
}
|
||||
|
||||
init(uuid: String, queue: DispatchQueue, config: NvimView.Config) {
|
||||
init(uuid: UUID, queue: DispatchQueue, config: NvimView.Config) {
|
||||
self.uuid = uuid
|
||||
|
||||
self.useInteractiveZsh = config.useInteractiveZsh
|
||||
@ -125,6 +126,10 @@ class UiBridge {
|
||||
return self.sendMessage(msgId: .resize, data: [width, height].data())
|
||||
}
|
||||
|
||||
func notifyReadinessForRpcEvents() -> Completable {
|
||||
return self.sendMessage(msgId: .readyForRpcEvents, data: nil)
|
||||
}
|
||||
|
||||
func focusGained(_ gained: Bool) -> Completable {
|
||||
return self.sendMessage(msgId: .focusGained, data: [gained].data())
|
||||
}
|
||||
@ -249,6 +254,9 @@ class UiBridge {
|
||||
guard let v = MessagePackUtils.value(from: data) else { return }
|
||||
self.streamSubject.onNext(.highlightAttrs(v))
|
||||
|
||||
case .rpcEventSubscribed:
|
||||
self.streamSubject.onNext(.rpcEventSubscribed)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,7 +327,7 @@ class UiBridge {
|
||||
|
||||
private let logger = LogContext.fileLogger(as: UiBridge.self, with: URL(fileURLWithPath: "/tmp/nvv-bridge.log"))
|
||||
|
||||
private let uuid: String
|
||||
private let uuid: UUID
|
||||
|
||||
private let useInteractiveZsh: Bool
|
||||
private let cwd: URL
|
||||
|
45
NvimView/NvimView/com.qvacua.NvimView.vim
Normal file
45
NvimView/NvimView/com.qvacua.NvimView.vim
Normal file
@ -0,0 +1,45 @@
|
||||
set termguicolors
|
||||
set mouse=a
|
||||
set title
|
||||
|
||||
"function! s:VimRMakeSessionTemporary() abort
|
||||
" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.make-session-temporary')
|
||||
"endfunction
|
||||
"command! -nargs=0 VimRMakeSessionTemporary call s:VimRMakeSessionTemporary(<args>)
|
||||
"
|
||||
"function! s:VimRMaximizeWindow() abort
|
||||
" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.maximize-window')
|
||||
"endfunction
|
||||
"command! -nargs=0 VimRMaximizeWindow call s:VimRMaximizeWindow(<args>)
|
||||
"
|
||||
"" -1: hide, 0: toggle, 1: show
|
||||
"function! s:VimRToggleTools(value) abort
|
||||
" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-tools', a:value)
|
||||
"endfunction
|
||||
"command! -nargs=0 VimRHideTools call s:VimRToggleTools(-1)
|
||||
"command! -nargs=0 VimRToggleTools call s:VimRToggleTools(0)
|
||||
"command! -nargs=0 VimRShowTools call s:VimRToggleTools(1)
|
||||
"
|
||||
"" -1: hide, 0: toggle, 1: show
|
||||
"function! s:VimRToggleToolButtons(value) abort
|
||||
" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-tool-buttons', a:value)
|
||||
"endfunction
|
||||
"command! -nargs=0 VimRHideToolButtons call s:VimRToggleToolButtons(-1)
|
||||
"command! -nargs=0 VimRToggleToolButtons call s:VimRToggleToolButtons(0)
|
||||
"command! -nargs=0 VimRShowToolButtons call s:VimRToggleToolButtons(1)
|
||||
"
|
||||
"function! s:VimRToggleFullscreen() abort
|
||||
" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-fullscreen')
|
||||
"endfunction
|
||||
"command! -nargs=0 VimRToggleFullscreen call s:VimRToggleFullscreen(<args>)
|
||||
"
|
||||
"function! s:VimRTest() abort
|
||||
" VimRMakeSessionTemporary
|
||||
" VimRHideTools
|
||||
" VimRMaximizeWindow
|
||||
" normal o
|
||||
"endfunction
|
||||
"command! -nargs=0 VimRTest call s:VimRTest()
|
||||
"
|
||||
""au VimEnter * echo "hello"
|
||||
""au GuiEnter * echo "world"
|
@ -1,3 +0,0 @@
|
||||
set termguicolors
|
||||
set mouse=a
|
||||
set title
|
@ -15,8 +15,8 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>SNAPSHOT-300</string>
|
||||
<string>SNAPSHOT-301</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>300</string>
|
||||
<string>301</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -41,12 +41,14 @@ typedef NS_ENUM(NSInteger, NvimServerMsgId) {
|
||||
NvimServerMsgIdColorSchemeChanged,
|
||||
NvimServerMsgIdDefaultColorsChanged,
|
||||
NvimServerMsgIdAutoCommandEvent,
|
||||
|
||||
NvimServerMsgIdRpcEventSubscribed,
|
||||
|
||||
NvimServerMsgIdDebug1,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, NvimBridgeMsgId) {
|
||||
NvimBridgeMsgIdAgentReady = 0,
|
||||
NvimBridgeMsgIdReadyForRpcEvents,
|
||||
NvimBridgeMsgIdInput,
|
||||
NvimBridgeMsgIdDeleteInput,
|
||||
NvimBridgeMsgIdResize,
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 9f731c05656fad98cc16bbbef7d1626b33695efc
|
||||
Subproject commit b212d045162eb07faee944220e96d27618c296e7
|
@ -16,6 +16,7 @@
|
||||
1929B0F599D1F62C7BE53D2C /* HttpServerMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B1DC584C89C477E83FA2 /* HttpServerMiddleware.swift */; };
|
||||
1929B1837C750CADB3A5BCB9 /* OpenQuicklyFileViewRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B1558455B3A74D93EF2A /* OpenQuicklyFileViewRow.swift */; };
|
||||
1929B20CE35B43BB1CE023BA /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BC2F05E9A5C0DB039739 /* Theme.swift */; };
|
||||
1929B250DB3FB395A700FE8C /* RpcEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BBF0944940845485A512 /* RpcEvents.swift */; };
|
||||
1929B29B95AD176D57942E08 /* UiRootReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B457B9D0FA4D21F3751E /* UiRootReducer.swift */; };
|
||||
1929B2D56C4652E251C23AD4 /* DefaultShortcuts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B93256AF7F9137223E36 /* DefaultShortcuts.swift */; };
|
||||
1929B3217A7A3D79E28C80DB /* PrefWindowReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B49E6924847AD085C8C9 /* PrefWindowReducer.swift */; };
|
||||
@ -26,6 +27,7 @@
|
||||
1929B3AC66EFE35D68C020E3 /* PreviewToolReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BFB0F294F3714D5E095F /* PreviewToolReducer.swift */; };
|
||||
1929B3F5743967125F357C9F /* Matcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BEEB33113B0E33C3830F /* Matcher.swift */; };
|
||||
1929B462CD4935AFF6D69457 /* FileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B7CB4863F80230C32D3C /* FileItem.swift */; };
|
||||
1929B489A51FD5B13888A00C /* RpcEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BBF0944940845485A512 /* RpcEvents.swift */; };
|
||||
1929B4B00D7BB191A9A6532D /* HtmlPreviewToolReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE5AEA3D0980860EED50 /* HtmlPreviewToolReducer.swift */; };
|
||||
1929B4B70926DE113E6BF990 /* PreviewReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE37AA2843779CAFA76F /* PreviewReducer.swift */; };
|
||||
1929B4E54E2F13A7F5F2B682 /* BufferListReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B67A10E6BB2986B2416E /* BufferListReducer.swift */; };
|
||||
@ -36,6 +38,7 @@
|
||||
1929B53876E6952D378C2B30 /* ScoredFileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BDF9EBAF1D9D44399045 /* ScoredFileItem.swift */; };
|
||||
1929B542A071BD03C846F6EF /* PrefUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B8241CDE58F7AAF89AE4 /* PrefUtils.swift */; };
|
||||
1929B5543B1E31A26096E656 /* FileMonitorReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B04EC69F616EEFAF5F96 /* FileMonitorReducer.swift */; };
|
||||
1929B560C6CE264FD1E1F5A3 /* com.qvacua.VimR.vim in Resources */ = {isa = PBXBuildFile; fileRef = 1929BC6D45B7E14D4D75D4E6 /* com.qvacua.VimR.vim */; };
|
||||
1929B59FA5C286E010F70BEE /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BFC0A5A9C6DB09BE1368 /* Types.swift */; };
|
||||
1929B5A2EE366F79ED32744C /* KeysPrefReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B88B5FA08E897A3C2168 /* KeysPrefReducer.swift */; };
|
||||
1929B5C1BABBC0D09D97C3EF /* PreviewMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B617C229B19DB3E987B8 /* PreviewMiddleware.swift */; };
|
||||
@ -352,7 +355,9 @@
|
||||
1929BB6608B4F0E037CA0F4C /* States.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = States.swift; sourceTree = "<group>"; };
|
||||
1929BBC84557C8351EC6183E /* FileItemIgnorePatternTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItemIgnorePatternTest.swift; sourceTree = "<group>"; };
|
||||
1929BBE0A534F2F6009D31BE /* AdvencedPref.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvencedPref.swift; sourceTree = "<group>"; };
|
||||
1929BBF0944940845485A512 /* RpcEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RpcEvents.swift; sourceTree = "<group>"; };
|
||||
1929BC2F05E9A5C0DB039739 /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
|
||||
1929BC6D45B7E14D4D75D4E6 /* com.qvacua.VimR.vim */ = {isa = PBXFileReference; lastKnownFileType = file.vim; path = com.qvacua.VimR.vim; sourceTree = "<group>"; };
|
||||
1929BCE3E156C06EDF1F2806 /* FileOutlineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileOutlineView.swift; sourceTree = "<group>"; };
|
||||
1929BD2CA8DD198A6BCDBCB7 /* ThemedTableSubviews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemedTableSubviews.swift; sourceTree = "<group>"; };
|
||||
1929BD4149D5A25C82064DD8 /* UiRoot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UiRoot.swift; sourceTree = "<group>"; };
|
||||
@ -817,6 +822,7 @@
|
||||
4BEBA50F1CFF374B00673FDF /* Info.plist */,
|
||||
4B37ADB81D6E471B00970D55 /* vimr */,
|
||||
4B3AC8931DB031C600AC5823 /* sparkle_pub.pem */,
|
||||
1929BC6D45B7E14D4D75D4E6 /* com.qvacua.VimR.vim */,
|
||||
);
|
||||
name = resources;
|
||||
sourceTree = "<group>";
|
||||
@ -878,6 +884,7 @@
|
||||
4B97E2CF1D33F92200FC0660 /* resources */,
|
||||
1929BA652D3B88FC071531EC /* UI */,
|
||||
1929B66A5E2D00EA143AFD86 /* RxRedux.swift */,
|
||||
1929BBF0944940845485A512 /* RpcEvents.swift */,
|
||||
);
|
||||
path = VimR;
|
||||
sourceTree = "<group>";
|
||||
@ -1067,6 +1074,7 @@
|
||||
4B9433E620B95EC6005807BA /* MacVim-log.icns in Resources */,
|
||||
4B94340D20B95EC7005807BA /* MacVim-dtd.icns in Resources */,
|
||||
4B9433DF20B95EC6005807BA /* MacVim-lisp.icns in Resources */,
|
||||
1929B560C6CE264FD1E1F5A3 /* com.qvacua.VimR.vim in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1182,6 +1190,7 @@
|
||||
1929BA269EBD68251410A08E /* ShortcutsTableSubviews.swift in Sources */,
|
||||
1929B2D56C4652E251C23AD4 /* DefaultShortcuts.swift in Sources */,
|
||||
1929B0C7150100A84FBDB8BF /* ShortcutItem.swift in Sources */,
|
||||
1929B250DB3FB395A700FE8C /* RpcEvents.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1216,6 +1225,7 @@
|
||||
1929BC682EA78BF50D1E0890 /* ShortcutsTableSubviews.swift in Sources */,
|
||||
1929B0244BD7111E168726CF /* DefaultShortcuts.swift in Sources */,
|
||||
1929BDC69A5F9D1661423488 /* ShortcutItem.swift in Sources */,
|
||||
1929B489A51FD5B13888A00C /* RpcEvents.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1310,7 +1320,7 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 300;
|
||||
CURRENT_PROJECT_VERSION = 301;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@ -1368,7 +1378,7 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 300;
|
||||
CURRENT_PROJECT_VERSION = 301;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
|
@ -50,7 +50,7 @@ class AppDelegateReducer: ReducerType {
|
||||
|
||||
var mainWindow = state.mainWindowTemplate
|
||||
|
||||
mainWindow.uuid = UUID().uuidString
|
||||
mainWindow.uuid = UUID()
|
||||
mainWindow.cwd = config.cwd
|
||||
mainWindow.isDirty = false
|
||||
|
||||
|
@ -220,6 +220,21 @@
|
||||
<action selector="toggleFileBrowser:" target="-1" id="Ggq-4w-iN7"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Toggle Buffer List" keyEquivalent="2" identifier="com.qvacua.vimr.menuitems.tools.toggle-buffer-list" id="OF4-kp-cNF">
|
||||
<connections>
|
||||
<action selector="toggleBufferList:" target="-1" id="bpT-lI-lYu"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Toggle Markdown Preview" keyEquivalent="3" identifier="com.qvacua.vimr.menuitems.tools.toggle-markdown-preview" id="rUg-f6-aPa">
|
||||
<connections>
|
||||
<action selector="toggleMarkdownPreview:" target="-1" id="buC-mL-NpJ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Toggle HTML Preview" keyEquivalent="4" identifier="com.qvacua.vimr.menuitems.tools.toggle-html-preview" id="RB0-mE-Gdd">
|
||||
<connections>
|
||||
<action selector="toggleHtmlPreview:" target="-1" id="KTN-ib-Iv6"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="XHW-5e-Vad"/>
|
||||
<menuItem title="Focus Neovim View" keyEquivalent="." identifier="com.qvacua.vimr.menuitems.tools.focus-neovim-view" id="TtL-Gg-pCj">
|
||||
<connections>
|
||||
@ -264,7 +279,8 @@
|
||||
<action selector="debug1:" target="-1" id="OSW-j0-HVo"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Debug 2" keyEquivalent="2" id="tWe-ll-a9P">
|
||||
<menuItem title="Debug 2" id="tWe-ll-a9P">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="debug2:" target="-1" id="r0m-FW-POU"/>
|
||||
</connections>
|
||||
|
@ -48,6 +48,11 @@ class BuffersList: NSView,
|
||||
source
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe(onNext: { state in
|
||||
if state.viewToBeFocused != nil,
|
||||
case .bufferList = state.viewToBeFocused! {
|
||||
self.beFirstResponder()
|
||||
}
|
||||
|
||||
let themeChanged = changeTheme(
|
||||
themePrefChanged: state.appearance.usesTheme != self.usesTheme,
|
||||
themeChanged: state.appearance.theme.mark != self.lastThemeMark,
|
||||
@ -73,7 +78,7 @@ class BuffersList: NSView,
|
||||
private let emit: (UuidAction<Action>) -> Void
|
||||
private let disposeBag = DisposeBag()
|
||||
|
||||
private let uuid: String
|
||||
private let uuid: UUID
|
||||
private var usesTheme: Bool
|
||||
private var showsFileIcon: Bool
|
||||
|
||||
|
@ -111,6 +111,24 @@ let defaultShortcuts: [String: [String: Any]] = [
|
||||
SRShortcutKeyCode: 18,
|
||||
SRShortcutModifierFlagsKey: 1048840,
|
||||
],
|
||||
"com.qvacua.vimr.menuitems.tools.toggle-buffer-list": [
|
||||
SRShortcutCharacters: "1",
|
||||
SRShortcutCharactersIgnoringModifiers: "2",
|
||||
SRShortcutKeyCode: 19,
|
||||
SRShortcutModifierFlagsKey: 1048840,
|
||||
],
|
||||
"com.qvacua.vimr.menuitems.tools.toggle-markdown-preview": [
|
||||
SRShortcutCharacters: "1",
|
||||
SRShortcutCharactersIgnoringModifiers: "3",
|
||||
SRShortcutKeyCode: 20,
|
||||
SRShortcutModifierFlagsKey: 1048840,
|
||||
],
|
||||
"com.qvacua.vimr.menuitems.tools.toggle-html-preview": [
|
||||
SRShortcutCharacters: "1",
|
||||
SRShortcutCharactersIgnoringModifiers: "4",
|
||||
SRShortcutKeyCode: 21,
|
||||
SRShortcutModifierFlagsKey: 1048840,
|
||||
],
|
||||
"com.qvacua.vimr.menuitems.tools.toggle-tool-buttons": [
|
||||
SRShortcutCharacters: "\\",
|
||||
SRShortcutCharactersIgnoringModifiers: "|",
|
||||
|
@ -67,7 +67,7 @@ class FileBrowser: NSView,
|
||||
private let emit: (UuidAction<Action>) -> Void
|
||||
private let disposeBag = DisposeBag()
|
||||
|
||||
private let uuid: String
|
||||
private let uuid: UUID
|
||||
|
||||
private var currentBufferUrl: URL?
|
||||
|
||||
|
@ -130,7 +130,7 @@ class FileOutlineView: NSOutlineView,
|
||||
private let emit: (UuidAction<FileBrowser.Action>) -> Void
|
||||
private let disposeBag = DisposeBag()
|
||||
|
||||
private let uuid: String
|
||||
private let uuid: UUID
|
||||
|
||||
private var root: Node
|
||||
private var cwd: URL {
|
||||
|
@ -45,6 +45,11 @@ class HtmlPreviewTool: NSView, UiComponent, WKNavigationDelegate {
|
||||
source
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe(onNext: { [unowned self] state in
|
||||
if state.viewToBeFocused != nil,
|
||||
case .htmlPreview = state.viewToBeFocused! {
|
||||
self.beFirstResponder()
|
||||
}
|
||||
|
||||
guard let serverUrl = state.htmlPreview.server, let htmlFileUrl = state.htmlPreview.htmlFile else {
|
||||
self.monitor = nil
|
||||
return
|
||||
@ -87,7 +92,7 @@ class HtmlPreviewTool: NSView, UiComponent, WKNavigationDelegate {
|
||||
}
|
||||
|
||||
private let emit: (UuidAction<Action>) -> Void
|
||||
private let uuid: String
|
||||
private let uuid: UUID
|
||||
|
||||
private var mark = Token()
|
||||
private var scrollTop = 0
|
||||
|
@ -1224,7 +1224,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>SNAPSHOT-300</string>
|
||||
<string>SNAPSHOT-301</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
@ -1241,7 +1241,7 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>300</string>
|
||||
<string>301</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.productivity</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
@ -80,7 +80,7 @@ class Logger {
|
||||
default: self.name = String(describing: name)
|
||||
}
|
||||
|
||||
self.logDateFormatter.dateFormat = "dd HH:mm:SSS"
|
||||
self.logDateFormatter.dateFormat = "dd HH:mm:ss.SSS"
|
||||
self.appender = appender
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,95 @@
|
||||
|
||||
import Cocoa
|
||||
import RxSwift
|
||||
import MessagePack
|
||||
|
||||
// MARK: - RpcEvent Actions
|
||||
extension MainWindow {
|
||||
|
||||
func rpcEventAction(params rawParams: [MessagePackValue]) {
|
||||
guard rawParams.count > 0 else { return }
|
||||
|
||||
guard let strEvent = rawParams[0].stringValue,
|
||||
let event = RpcEvent(rawValue: "\(RpcEvent.prefix).\(strEvent)")
|
||||
else {
|
||||
return
|
||||
}
|
||||
let params = Array(rawParams.suffix(from: 1))
|
||||
|
||||
stdoutLog.debug("\(event): \(params)")
|
||||
|
||||
switch event {
|
||||
case .makeSessionTemporary:
|
||||
self.emit(self.uuidAction(for: .makeSessionTemporary))
|
||||
|
||||
case .maximizeWindow:
|
||||
guard let screen = self.window.screen else { return }
|
||||
self.window.setFrame(screen.frame, display: true)
|
||||
|
||||
case .toggleTools:
|
||||
if params.count == 0 { return }
|
||||
|
||||
let param = params[0].integerValue
|
||||
|
||||
if params.isEmpty || param == 0 {
|
||||
self.toggleAllTools(self)
|
||||
} else if param == -1 {
|
||||
self.hideAllTools()
|
||||
} else if param == 1 {
|
||||
self.showAllTools()
|
||||
}
|
||||
|
||||
case .toggleToolButtons:
|
||||
if params.count == 0 { return }
|
||||
|
||||
let param = params[0].integerValue
|
||||
|
||||
if params.isEmpty || param == 0 {
|
||||
self.toggleToolButtons(self)
|
||||
} else if param == -1 {
|
||||
self.hideToolButtons()
|
||||
} else if param == 1 {
|
||||
self.showToolButtons()
|
||||
}
|
||||
|
||||
case .toggleFullScreen:
|
||||
self.window.toggleFullScreen(self)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private func hideToolButtons() {
|
||||
self.workspace.hideToolButtons()
|
||||
self.focusNvimView(self)
|
||||
self.emit(self.uuidAction(
|
||||
for: .toggleToolButtons(self.workspace.isToolButtonsVisible)
|
||||
))
|
||||
}
|
||||
|
||||
private func showToolButtons() {
|
||||
self.workspace.showToolButtons()
|
||||
self.focusNvimView(self)
|
||||
self.emit(self.uuidAction(
|
||||
for: .toggleToolButtons(self.workspace.isToolButtonsVisible)
|
||||
))
|
||||
}
|
||||
|
||||
private func hideAllTools() {
|
||||
self.workspace.hideAllTools()
|
||||
self.focusNvimView(self)
|
||||
self.emit(self.uuidAction(
|
||||
for: .toggleAllTools(self.workspace.isAllToolsVisible)
|
||||
))
|
||||
}
|
||||
|
||||
private func showAllTools() {
|
||||
self.workspace.showAllTools()
|
||||
self.focusNvimView(self)
|
||||
self.emit(self.uuidAction(
|
||||
for: .toggleAllTools(self.workspace.isAllToolsVisible)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - File Menu Item Actions
|
||||
extension MainWindow {
|
||||
@ -123,26 +212,43 @@ extension MainWindow {
|
||||
}
|
||||
|
||||
@IBAction func toggleFileBrowser(_ sender: Any?) {
|
||||
let fileBrowser = self.fileBrowserContainer
|
||||
guard let fileBrowser = self.fileBrowserContainer else { return }
|
||||
self.toggle(tool: fileBrowser, toolType: .fileBrowser)
|
||||
}
|
||||
|
||||
if fileBrowser?.isSelected == true {
|
||||
if fileBrowser?.view.isFirstResponder == true {
|
||||
fileBrowser?.toggle()
|
||||
@IBAction func toggleBufferList(_ sender: Any?) {
|
||||
guard let bufferList = self.buffersListContainer else { return }
|
||||
self.toggle(tool: bufferList, toolType: .bufferList)
|
||||
}
|
||||
|
||||
@IBAction func toggleMarkdownPreview(_ sender: Any?) {
|
||||
guard let markdownPreview = self.previewContainer else { return }
|
||||
self.toggle(tool: markdownPreview, toolType: .markdownPreview)
|
||||
}
|
||||
|
||||
@IBAction func toggleHtmlPreview(_ sender: Any?) {
|
||||
guard let htmlPreview = self.htmlPreviewContainer else { return }
|
||||
self.toggle(tool: htmlPreview, toolType: .htmlPreview)
|
||||
}
|
||||
|
||||
@IBAction func focusNvimView(_: Any?) {
|
||||
self.emit(self.uuidAction(for: .focus(.neoVimView)))
|
||||
}
|
||||
|
||||
private func toggle(tool: WorkspaceTool, toolType: FocusableView) {
|
||||
if tool.isSelected == true {
|
||||
if tool.view.isFirstResponder == true {
|
||||
tool.toggle()
|
||||
self.focusNvimView(self)
|
||||
} else {
|
||||
self.emit(self.uuidAction(for: .focus(.fileBrowser)))
|
||||
self.emit(self.uuidAction(for: .focus(toolType)))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
fileBrowser?.toggle()
|
||||
self.emit(self.uuidAction(for: .focus(.fileBrowser)))
|
||||
}
|
||||
|
||||
@IBAction func focusNvimView(_: Any?) {
|
||||
// self.window.makeFirstResponder(self.neoVimView)
|
||||
self.emit(self.uuidAction(for: .focus(.neoVimView)))
|
||||
tool.toggle()
|
||||
self.emit(self.uuidAction(for: .focus(toolType)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,8 @@ class MainWindow: NSObject,
|
||||
case setState(for: Tools, with: WorkspaceTool)
|
||||
case setToolsState([(Tools, WorkspaceTool)])
|
||||
|
||||
case makeSessionTemporary
|
||||
|
||||
case setTheme(Theme)
|
||||
|
||||
case close
|
||||
@ -49,12 +51,21 @@ class MainWindow: NSObject,
|
||||
|
||||
case neoVimView
|
||||
case fileBrowser
|
||||
case preview
|
||||
case bufferList
|
||||
case markdownPreview
|
||||
case htmlPreview
|
||||
}
|
||||
|
||||
enum Tools: String, Codable {
|
||||
|
||||
static let all = Set([Tools.fileBrowser, Tools.buffersList, Tools.preview, Tools.htmlPreview])
|
||||
static let all = Set(
|
||||
[
|
||||
Tools.fileBrowser,
|
||||
Tools.buffersList,
|
||||
Tools.preview,
|
||||
Tools.htmlPreview
|
||||
]
|
||||
)
|
||||
|
||||
case fileBrowser = "com.qvacua.vimr.tools.file-browser"
|
||||
case buffersList = "com.qvacua.vimr.tools.opened-files-list"
|
||||
@ -71,7 +82,7 @@ class MainWindow: NSObject,
|
||||
case verticalSplit
|
||||
}
|
||||
|
||||
let uuid: String
|
||||
let uuid: UUID
|
||||
let emit: (UuidAction<Action>) -> Void
|
||||
|
||||
let windowController: NSWindowController
|
||||
@ -102,18 +113,33 @@ class MainWindow: NSObject,
|
||||
var isClosing = false
|
||||
let cliPipePath: String?
|
||||
|
||||
required init(source: Observable<StateType>, emitter: ActionEmitter, state: StateType) {
|
||||
required init(
|
||||
source: Observable<StateType>,
|
||||
emitter: ActionEmitter,
|
||||
state: StateType
|
||||
) {
|
||||
self.emit = emitter.typedEmit()
|
||||
self.uuid = state.uuid
|
||||
|
||||
self.cliPipePath = state.cliPipePath
|
||||
|
||||
self.windowController = NSWindowController(windowNibName: NSNib.Name("MainWindow"))
|
||||
self.windowController = NSWindowController(
|
||||
windowNibName: NSNib.Name("MainWindow")
|
||||
)
|
||||
|
||||
let neoVimViewConfig = NvimView.Config(useInteractiveZsh: state.useInteractiveZsh,
|
||||
cwd: state.cwd,
|
||||
nvimArgs: state.nvimArgs,
|
||||
envDict: state.envDict)
|
||||
var sourceFileUrls = [URL]()
|
||||
if let sourceFileUrl = Bundle(for: MainWindow.self)
|
||||
.url(forResource: "com.qvacua.VimR", withExtension: "vim") {
|
||||
sourceFileUrls.append(sourceFileUrl)
|
||||
}
|
||||
|
||||
let neoVimViewConfig = NvimView.Config(
|
||||
useInteractiveZsh: state.useInteractiveZsh,
|
||||
cwd: state.cwd,
|
||||
nvimArgs: state.nvimArgs,
|
||||
envDict: state.envDict,
|
||||
sourceFiles: sourceFileUrls
|
||||
)
|
||||
self.neoVimView = NvimView(frame: .zero, config: neoVimViewConfig)
|
||||
self.neoVimView.configureForAutoLayout()
|
||||
|
||||
@ -122,9 +148,11 @@ class MainWindow: NSObject,
|
||||
var tools: [Tools: WorkspaceTool] = [:]
|
||||
if state.activeTools[.preview] == true {
|
||||
self.preview = PreviewTool(source: source, emitter: emitter, state: state)
|
||||
let previewConfig = WorkspaceTool.Config(title: "Markdown",
|
||||
view: self.preview!,
|
||||
customMenuItems: self.preview!.menuItems)
|
||||
let previewConfig = WorkspaceTool.Config(
|
||||
title: "Markdown",
|
||||
view: self.preview!,
|
||||
customMenuItems: self.preview!.menuItems
|
||||
)
|
||||
self.previewContainer = WorkspaceTool(previewConfig)
|
||||
self.previewContainer!.dimension = state.tools[.preview]?.dimension ?? 250
|
||||
tools[.preview] = self.previewContainer
|
||||
@ -132,30 +160,43 @@ class MainWindow: NSObject,
|
||||
|
||||
if state.activeTools[.htmlPreview] == true {
|
||||
self.htmlPreview = HtmlPreviewTool(source: source, emitter: emitter, state: state)
|
||||
let htmlPreviewConfig = WorkspaceTool.Config(title: "HTML",
|
||||
view: self.htmlPreview!,
|
||||
customToolbar: self.htmlPreview!.innerCustomToolbar)
|
||||
let htmlPreviewConfig = WorkspaceTool.Config(
|
||||
title: "HTML",
|
||||
view: self.htmlPreview!,
|
||||
customToolbar: self.htmlPreview!.innerCustomToolbar
|
||||
)
|
||||
self.htmlPreviewContainer = WorkspaceTool(htmlPreviewConfig)
|
||||
self.htmlPreviewContainer!.dimension = state.tools[.htmlPreview]?.dimension ?? 250
|
||||
tools[.htmlPreview] = self.htmlPreviewContainer
|
||||
}
|
||||
|
||||
if state.activeTools[.fileBrowser] == true {
|
||||
self.fileBrowser = FileBrowser(source: source, emitter: emitter, state: state)
|
||||
let fileBrowserConfig = WorkspaceTool.Config(title: "Files",
|
||||
view: self.fileBrowser!,
|
||||
customToolbar: self.fileBrowser!.innerCustomToolbar,
|
||||
customMenuItems: self.fileBrowser!.menuItems)
|
||||
self.fileBrowser = FileBrowser(
|
||||
source: source, emitter: emitter, state: state
|
||||
)
|
||||
let fileBrowserConfig = WorkspaceTool.Config(
|
||||
title: "Files",
|
||||
view: self.fileBrowser!,
|
||||
customToolbar: self.fileBrowser!.innerCustomToolbar,
|
||||
customMenuItems: self.fileBrowser!.menuItems
|
||||
)
|
||||
self.fileBrowserContainer = WorkspaceTool(fileBrowserConfig)
|
||||
self.fileBrowserContainer!.dimension = state.tools[.fileBrowser]?.dimension ?? 200
|
||||
self.fileBrowserContainer!.dimension = state
|
||||
.tools[.fileBrowser]?
|
||||
.dimension ?? 200
|
||||
tools[.fileBrowser] = self.fileBrowserContainer
|
||||
}
|
||||
|
||||
if state.activeTools[.buffersList] == true {
|
||||
self.buffersList = BuffersList(source: source, emitter: emitter, state: state)
|
||||
let buffersListConfig = WorkspaceTool.Config(title: "Buffers", view: self.buffersList!)
|
||||
self.buffersList = BuffersList(
|
||||
source: source, emitter: emitter, state: state
|
||||
)
|
||||
let buffersListConfig = WorkspaceTool.Config(title: "Buffers",
|
||||
view: self.buffersList!)
|
||||
self.buffersListContainer = WorkspaceTool(buffersListConfig)
|
||||
self.buffersListContainer!.dimension = state.tools[.buffersList]?.dimension ?? 200
|
||||
self.buffersListContainer!.dimension = state
|
||||
.tools[.buffersList]?
|
||||
.dimension ?? 200
|
||||
tools[.buffersList] = self.buffersListContainer
|
||||
}
|
||||
|
||||
@ -181,7 +222,8 @@ class MainWindow: NSObject,
|
||||
return
|
||||
}
|
||||
|
||||
self.workspace.append(tool: tool, location: state.tools[toolId]?.location ?? .left)
|
||||
self.workspace.append(tool: tool,
|
||||
location: state.tools[toolId]?.location ?? .left)
|
||||
}
|
||||
|
||||
self.tools.forEach { (toolId, toolContainer) in
|
||||
@ -203,7 +245,9 @@ class MainWindow: NSObject,
|
||||
|
||||
self.addViews()
|
||||
|
||||
self.neoVimView.trackpadScrollResistance = CGFloat(state.trackpadScrollResistance)
|
||||
self.neoVimView.trackpadScrollResistance = CGFloat(
|
||||
state.trackpadScrollResistance
|
||||
)
|
||||
self.neoVimView.usesLiveResize = state.useLiveResize
|
||||
self.updateNeoVimAppearance()
|
||||
|
||||
@ -229,14 +273,24 @@ class MainWindow: NSObject,
|
||||
case .newCurrentBuffer(let curBuf): self.newCurrentBuffer(curBuf)
|
||||
case .bufferWritten(let buf): self.bufferWritten(buf)
|
||||
case .colorschemeChanged(let theme): self.colorschemeChanged(to: theme)
|
||||
case .ipcBecameInvalid(let reason): self.ipcBecameInvalid(reason: reason)
|
||||
|
||||
case .ipcBecameInvalid(let reason):
|
||||
self.ipcBecameInvalid(reason: reason)
|
||||
|
||||
case .scroll: self.scroll()
|
||||
case .cursor(let position): self.cursor(to: position)
|
||||
case .initVimError: self.showInitError()
|
||||
|
||||
case .apiError(let error, let msg):
|
||||
fileLog.error("Got api error with msg '\(msg)' and error: \(error)")
|
||||
break
|
||||
|
||||
case .rpcEvent(let method, let params):
|
||||
self.rpcEventAction(params: params)
|
||||
|
||||
case .rpcEventSubscribed:
|
||||
break
|
||||
|
||||
}
|
||||
}, onError: { error in
|
||||
// FIXME call onError
|
||||
@ -251,7 +305,8 @@ class MainWindow: NSObject,
|
||||
return
|
||||
}
|
||||
|
||||
if state.viewToBeFocused != nil, case .neoVimView = state.viewToBeFocused! {
|
||||
if state.viewToBeFocused != nil,
|
||||
case .neoVimView = state.viewToBeFocused! {
|
||||
self.window.makeFirstResponder(self.neoVimView)
|
||||
}
|
||||
|
||||
@ -269,7 +324,9 @@ class MainWindow: NSObject,
|
||||
&& state.preview.previewPosition.hasDifferentMark(as: self.previewPosition) {
|
||||
|
||||
self.previewPosition = state.preview.previewPosition
|
||||
return self.neoVimView.cursorGo(to: state.preview.previewPosition.payload)
|
||||
return self.neoVimView.cursorGo(
|
||||
to: state.preview.previewPosition.payload
|
||||
)
|
||||
}
|
||||
|
||||
return .empty()
|
||||
@ -303,10 +360,13 @@ class MainWindow: NSObject,
|
||||
}
|
||||
|
||||
_ = changeTheme(
|
||||
themePrefChanged: themePrefChanged, themeChanged: themeChanged, usesTheme: usesTheme,
|
||||
themePrefChanged: themePrefChanged,
|
||||
themeChanged: themeChanged,
|
||||
usesTheme: usesTheme,
|
||||
forTheme: {
|
||||
self.themeTitlebar(grow: !self.titlebarThemed)
|
||||
self.window.backgroundColor = state.appearance.theme.payload.background.brightening(by: 0.9)
|
||||
self.window.backgroundColor = state.appearance
|
||||
.theme.payload.background.brightening(by: 0.9)
|
||||
|
||||
self.set(workspaceThemeWith: state.appearance.theme.payload)
|
||||
self.lastThemeMark = state.appearance.theme.mark
|
||||
@ -445,8 +505,10 @@ class MainWindow: NSObject,
|
||||
case .default: return self.neoVimView.open(urls: [url])
|
||||
case .currentTab: return self.neoVimView.openInCurrentTab(url: url)
|
||||
case .newTab: return self.neoVimView.openInNewTab(urls: [url])
|
||||
case .horizontalSplit: return self.neoVimView.openInHorizontalSplit(urls: [url])
|
||||
case .verticalSplit: return self.neoVimView.openInVerticalSplit(urls: [url])
|
||||
case .horizontalSplit:
|
||||
return self.neoVimView.openInHorizontalSplit(urls: [url])
|
||||
case .verticalSplit:
|
||||
return self.neoVimView.openInVerticalSplit(urls: [url])
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -460,10 +522,11 @@ class MainWindow: NSObject,
|
||||
private func showInitError() {
|
||||
let notification = NSUserNotification()
|
||||
notification.title = "Error during initialization"
|
||||
notification.informativeText = """
|
||||
There was an error during the initialization of NeoVim.
|
||||
Use :messages to view the error messages.
|
||||
"""
|
||||
notification
|
||||
.informativeText = """
|
||||
There was an error during the initialization of NeoVim.
|
||||
Use :messages to view the error messages.
|
||||
"""
|
||||
|
||||
NSUserNotificationCenter.default.deliver(notification)
|
||||
}
|
||||
|
@ -78,6 +78,9 @@ class MainWindowReducer: ReducerType {
|
||||
case let .setTheme(theme):
|
||||
state.appearance.theme = Marked(theme)
|
||||
|
||||
case .makeSessionTemporary:
|
||||
state.isTemporarySession = true
|
||||
|
||||
default:
|
||||
return tuple
|
||||
|
||||
|
@ -34,7 +34,7 @@ class PreviewMiddleware {
|
||||
self.template = template
|
||||
}
|
||||
|
||||
func apply(_ state: MainWindow.State, uuid: String) {
|
||||
func apply(_ state: MainWindow.State, uuid: UUID) {
|
||||
let preview = state.preview
|
||||
guard let buffer = preview.buffer, let html = preview.html else {
|
||||
guard let previewUrl = self.previewFiles[uuid] else {
|
||||
@ -80,7 +80,7 @@ class PreviewMiddleware {
|
||||
}
|
||||
|
||||
private let template: String
|
||||
private var previewFiles = [String: URL]()
|
||||
private var previewFiles = [UUID: URL]()
|
||||
}
|
||||
|
||||
class PreviewToolMiddleware: MiddlewareType {
|
||||
|
@ -80,7 +80,8 @@ class PreviewTool: NSView, UiComponent, WKNavigationDelegate {
|
||||
source
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe(onNext: { state in
|
||||
if state.viewToBeFocused != nil, case .preview = state.viewToBeFocused! {
|
||||
if state.viewToBeFocused != nil,
|
||||
case .markdownPreview = state.viewToBeFocused! {
|
||||
self.beFirstResponder()
|
||||
}
|
||||
|
||||
@ -143,7 +144,7 @@ class PreviewTool: NSView, UiComponent, WKNavigationDelegate {
|
||||
}
|
||||
|
||||
private let emit: (UuidAction<Action>) -> Void
|
||||
private let uuid: String
|
||||
private let uuid: UUID
|
||||
|
||||
private let webview: WKWebView
|
||||
private let disposeBag = DisposeBag()
|
||||
|
@ -40,7 +40,7 @@ class PreviewUtils {
|
||||
}
|
||||
}
|
||||
|
||||
static func state(for uuid: String,
|
||||
static func state(for uuid: UUID,
|
||||
baseUrl: URL,
|
||||
buffer: NvimView.Buffer?,
|
||||
editorPosition: Marked<Position>,
|
||||
@ -72,11 +72,11 @@ class PreviewUtils {
|
||||
previewPosition: previewPosition)
|
||||
}
|
||||
|
||||
private static func serverUrl(for uuid: String, baseUrl: URL, lastComponent: String) -> URL {
|
||||
private static func serverUrl(for uuid: UUID, baseUrl: URL, lastComponent: String) -> URL {
|
||||
return baseUrl.appendingPathComponent("\(uuid)/\(markdownPath)/\(lastComponent)")
|
||||
}
|
||||
|
||||
private static func htmlUrl(with uuid: String) -> URL {
|
||||
private static func htmlUrl(with uuid: UUID) -> URL {
|
||||
return self.tempDir.appendingPathComponent("\(uuid)-markdown-index.html")
|
||||
}
|
||||
|
||||
|
17
VimR/VimR/RpcEvents.swift
Normal file
17
VimR/VimR/RpcEvents.swift
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
enum RpcEvent: String, CaseIterable {
|
||||
|
||||
static let prefix = "com.qvacua.vimr.rpc-events"
|
||||
|
||||
case makeSessionTemporary = "com.qvacua.vimr.rpc-events.make-session-temporary"
|
||||
case maximizeWindow = "com.qvacua.vimr.rpc-events.maximize-window"
|
||||
case toggleTools = "com.qvacua.vimr.rpc-events.toggle-tools"
|
||||
case toggleToolButtons = "com.qvacua.vimr.rpc-events.toggle-tool-buttons"
|
||||
case toggleFullScreen = "com.qvacua.vimr.rpc-events.toggle-fullscreen"
|
||||
}
|
@ -38,9 +38,9 @@ struct AppState: Codable {
|
||||
var preferencesOpen = Marked(false)
|
||||
|
||||
var mainWindowTemplate = MainWindow.State.default
|
||||
var currentMainWindowUuid: String?
|
||||
var currentMainWindowUuid: UUID?
|
||||
|
||||
var mainWindows: [String: MainWindow.State] = [:]
|
||||
var mainWindows: [UUID: MainWindow.State] = [:]
|
||||
|
||||
var openQuickly = OpenQuicklyWindow.State.default
|
||||
|
||||
@ -264,8 +264,10 @@ extension MainWindow {
|
||||
var trackpadScrollResistance = 5.0
|
||||
var useLiveResize = false
|
||||
|
||||
var isTemporarySession = false
|
||||
|
||||
// neovim
|
||||
var uuid = UUID().uuidString
|
||||
var uuid = UUID()
|
||||
var currentBuffer: NvimView.Buffer?
|
||||
var buffers = [NvimView.Buffer]()
|
||||
var cwd = FileUtils.userHomeUrl
|
||||
|
@ -15,19 +15,19 @@ struct StateActionPair<S, A> {
|
||||
|
||||
protocol UuidTagged {
|
||||
|
||||
var uuid: String { get }
|
||||
var uuid: UUID { get }
|
||||
}
|
||||
|
||||
class UuidAction<A>: UuidTagged, CustomStringConvertible {
|
||||
|
||||
let uuid: String
|
||||
let uuid: UUID
|
||||
let payload: A
|
||||
|
||||
var description: String {
|
||||
return "UuidAction(uuid: \(uuid), payload: \(String(reflecting: payload)))"
|
||||
}
|
||||
|
||||
init(uuid: String, action: A) {
|
||||
init(uuid: UUID, action: A) {
|
||||
self.uuid = uuid
|
||||
self.payload = action
|
||||
}
|
||||
@ -35,14 +35,14 @@ class UuidAction<A>: UuidTagged, CustomStringConvertible {
|
||||
|
||||
class UuidState<S>: UuidTagged, CustomStringConvertible {
|
||||
|
||||
let uuid: String
|
||||
let uuid: UUID
|
||||
let payload: S
|
||||
|
||||
var description: String {
|
||||
return "UuidState(uuid: \(uuid), payload: \(String(reflecting: payload)))"
|
||||
}
|
||||
|
||||
init(uuid: String, state: S) {
|
||||
init(uuid: UUID, state: S) {
|
||||
self.uuid = uuid
|
||||
self.payload = state
|
||||
}
|
||||
@ -127,4 +127,4 @@ class UiComponentTemplate: UiComponent {
|
||||
private let disposeBag = DisposeBag()
|
||||
|
||||
private let someField: String
|
||||
}
|
||||
}
|
||||
|
@ -79,8 +79,8 @@ class UiRoot: UiComponent {
|
||||
private let openQuicklyWindow: OpenQuicklyWindow
|
||||
private let prefWindow: PrefWindow
|
||||
|
||||
private var mainWindows = [String: MainWindow]()
|
||||
private var subjectForMainWindows = [String: CompletableSubject<MainWindow.State>]()
|
||||
private var mainWindows = [UUID: MainWindow]()
|
||||
private var subjectForMainWindows = [UUID: CompletableSubject<MainWindow.State>]()
|
||||
|
||||
private func newMainWindow(with state: MainWindow.State) -> MainWindow {
|
||||
let subject = self.source.mapOmittingNil { $0.mainWindows[state.uuid] }.completableSubject()
|
||||
@ -89,7 +89,7 @@ class UiRoot: UiComponent {
|
||||
return MainWindow(source: subject.asObservable(), emitter: self.emitter, state: state)
|
||||
}
|
||||
|
||||
private func removeMainWindow(with uuid: String) {
|
||||
private func removeMainWindow(with uuid: UUID) {
|
||||
self.subjectForMainWindows[uuid]?.onCompleted()
|
||||
|
||||
self.subjectForMainWindows.removeValue(forKey: uuid)
|
||||
|
@ -38,6 +38,11 @@ class UiRootReducer: ReducerType {
|
||||
|
||||
case let .becomeKey(isFullScreen):
|
||||
appState.currentMainWindowUuid = uuid
|
||||
|
||||
if appState.mainWindows[uuid]?.isTemporarySession == true {
|
||||
break
|
||||
}
|
||||
|
||||
appState.mainWindowTemplate = self.mainWindowTemplate(
|
||||
from: appState.mainWindowTemplate,
|
||||
new: appState.mainWindows[uuid] ?? appState.mainWindowTemplate,
|
||||
@ -45,20 +50,40 @@ class UiRootReducer: ReducerType {
|
||||
)
|
||||
|
||||
case let .frameChanged(to:frame):
|
||||
if appState.mainWindows[uuid]?.isTemporarySession == true {
|
||||
break
|
||||
}
|
||||
|
||||
if uuid == appState.currentMainWindowUuid {
|
||||
appState.mainWindowTemplate.frame = frame
|
||||
}
|
||||
|
||||
case let .setToolsState(tools):
|
||||
if appState.mainWindows[uuid]?.isTemporarySession == true {
|
||||
break
|
||||
}
|
||||
|
||||
appState.mainWindowTemplate.orderedTools = tools.map { $0.0 }
|
||||
|
||||
case let .toggleAllTools(value):
|
||||
if appState.mainWindows[uuid]?.isTemporarySession == true {
|
||||
break
|
||||
}
|
||||
|
||||
appState.mainWindowTemplate.isAllToolsVisible = value
|
||||
|
||||
case let .toggleToolButtons(value):
|
||||
if appState.mainWindows[uuid]?.isTemporarySession == true {
|
||||
break
|
||||
}
|
||||
|
||||
appState.mainWindowTemplate.isToolButtonsVisible = value
|
||||
|
||||
case .close:
|
||||
if appState.mainWindows[uuid]?.isTemporarySession == true {
|
||||
break
|
||||
}
|
||||
|
||||
if appState.currentMainWindowUuid == uuid, let mainWindowToClose = appState.mainWindows[uuid] {
|
||||
appState.mainWindowTemplate = self.mainWindowTemplate(from: appState.mainWindowTemplate,
|
||||
new: mainWindowToClose,
|
||||
|
@ -127,10 +127,34 @@ class Workspace: NSView, WorkspaceBarDelegate {
|
||||
self.delegate?.moved(tool: tool)
|
||||
}
|
||||
|
||||
func hideAllTools() {
|
||||
if self.isAllToolsVisible {
|
||||
self.isAllToolsVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
func showAllTools() {
|
||||
if !self.isAllToolsVisible {
|
||||
self.isAllToolsVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
func toggleAllTools() {
|
||||
self.isAllToolsVisible = !self.isAllToolsVisible
|
||||
}
|
||||
|
||||
func hideToolButtons() {
|
||||
if self.isToolButtonsVisible {
|
||||
self.isToolButtonsVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
func showToolButtons() {
|
||||
if !self.isToolButtonsVisible {
|
||||
self.isToolButtonsVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
func toggleToolButtons() {
|
||||
self.isToolButtonsVisible = !self.isToolButtonsVisible
|
||||
}
|
||||
|
30
VimR/VimR/com.qvacua.VimR.vim
Normal file
30
VimR/VimR/com.qvacua.VimR.vim
Normal file
@ -0,0 +1,30 @@
|
||||
function! s:VimRMakeSessionTemporary() abort
|
||||
call rpcnotify(0, 'com.qvacua.NvimView', 'make-session-temporary')
|
||||
endfunction
|
||||
command! -nargs=0 VimRMakeSessionTemporary call s:VimRMakeSessionTemporary(<args>)
|
||||
|
||||
function! s:VimRMaximizeWindow() abort
|
||||
call rpcnotify(0, 'com.qvacua.NvimView', 'maximize-window')
|
||||
endfunction
|
||||
command! -nargs=0 VimRMaximizeWindow call s:VimRMaximizeWindow(<args>)
|
||||
|
||||
" -1: hide, 0: toggle, 1: show
|
||||
function! s:VimRToggleTools(value) abort
|
||||
call rpcnotify(0, 'com.qvacua.NvimView', 'toggle-tools', a:value)
|
||||
endfunction
|
||||
command! -nargs=0 VimRHideTools call s:VimRToggleTools(-1)
|
||||
command! -nargs=0 VimRToggleTools call s:VimRToggleTools(0)
|
||||
command! -nargs=0 VimRShowTools call s:VimRToggleTools(1)
|
||||
|
||||
" -1: hide, 0: toggle, 1: show
|
||||
function! s:VimRToggleToolButtons(value) abort
|
||||
call rpcnotify(0, 'com.qvacua.NvimView', 'toggle-tool-buttons', a:value)
|
||||
endfunction
|
||||
command! -nargs=0 VimRHideToolButtons call s:VimRToggleToolButtons(-1)
|
||||
command! -nargs=0 VimRToggleToolButtons call s:VimRToggleToolButtons(0)
|
||||
command! -nargs=0 VimRShowToolButtons call s:VimRToggleToolButtons(1)
|
||||
|
||||
function! s:VimRToggleFullscreen() abort
|
||||
call rpcnotify(0, 'com.qvacua.NvimView', 'toggle-fullscreen')
|
||||
endfunction
|
||||
command! -nargs=0 VimRToggleFullscreen call s:VimRToggleFullscreen(<args>)
|
@ -15,10 +15,10 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>SNAPSHOT-300</string>
|
||||
<string>SNAPSHOT-301</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>300</string>
|
||||
<string>301</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -1,6 +1,8 @@
|
||||
# 0.26.0-???
|
||||
|
||||
* GH-314: You can customize the key shortcut for all menu items in the *Shortcut* preferences pane.
|
||||
* GH-501: Add key shortcuts to toggle the Buffer List, Markdown Preview, and HTML Preview tools.
|
||||
* GH-649: Add commands that can control some of GUI elements.
|
||||
* Draw the disclosure triangle in appropriate color of the current color scheme (and improve handling of changes of `cwd` in the file browser).
|
||||
* ...
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user