Showing preview only (5,973K chars total). Download the full file or copy to clipboard to get everything.
Repository: qvacua/vimr
Branch: master
Commit: 371354a7e126
Files: 376
Total size: 5.6 MB
Directory structure:
gitextract_y2whn9_4/
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ └── build-universal-neovim.yml
├── .gitignore
├── .gitmodules
├── .swiftformat
├── .swiftlint.yml
├── Brewfile
├── Commons/
│ ├── .gitignore
│ ├── Package.swift
│ ├── README.md
│ ├── Sources/
│ │ ├── Commons/
│ │ │ ├── AppKitCommons.swift
│ │ │ ├── ConditionVariable.swift
│ │ │ ├── CoreCommons.swift
│ │ │ ├── Defs.swift
│ │ │ ├── FifoCache.swift
│ │ │ ├── FileUtils.swift
│ │ │ ├── FoundationCommons.swift
│ │ │ ├── LoggerCommons.swift
│ │ │ ├── ProcessUtils.swift
│ │ │ └── SwiftCommons.swift
│ │ └── CommonsObjC/
│ │ ├── NetUtils.m
│ │ └── include/
│ │ └── NetUtils.h
│ ├── Support/
│ │ ├── CommonsSupport.xcodeproj/
│ │ │ └── project.pbxproj
│ │ └── EnvVarTest/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AccentColor.colorset/
│ │ │ │ └── Contents.json
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ └── MainMenu.xib
│ │ └── Info.plist
│ └── Tests/
│ └── CommonsTests/
│ ├── ArrayCommonsTest.swift
│ ├── DictionaryCommonsTest.swift
│ ├── FifoCacheTest.swift
│ ├── FileUtilsTest.swift
│ ├── Resources/
│ │ ├── FileUtilsTest/
│ │ │ ├── a1/
│ │ │ │ ├── a1-file1
│ │ │ │ └── a2/
│ │ │ │ └── a1-a2-file1
│ │ │ └── b1/
│ │ │ └── b1-file1
│ │ └── UrlCommonsTest/
│ │ ├── .dot-hidden-file
│ │ └── dummy.rtfd/
│ │ └── TXT.rtf
│ ├── StringCommonsTest.swift
│ ├── SwiftCommonsTest.swift
│ └── UrlCommonsTest.swift
├── DEVELOP.md
├── Ignore/
│ ├── Package.swift
│ ├── README.md
│ ├── Sources/
│ │ └── Ignore/
│ │ ├── FileLineReader.swift
│ │ ├── Filter.swift
│ │ ├── GitUtils.swift
│ │ └── Ignore.swift
│ └── Tests/
│ └── IgnoreTests/
│ ├── FileLineReaderTest.swift
│ ├── FilterTest.swift
│ ├── IgnoreSplitTest.swift
│ ├── IgnoreTest.swift
│ └── Resources/
│ ├── FileLineReaderTest/
│ │ ├── dos-no-line-ending-at-the-end.txt
│ │ ├── dos-only-new-lines.txt
│ │ ├── dos-with-line-ending-at-the-end.txt
│ │ ├── empty.txt
│ │ ├── unix-no-line-ending-at-the-end.txt
│ │ ├── unix-only-new-lines.txt
│ │ └── unix-with-line-ending-at-the-end.txt
│ └── IgnoreCollectionTest/
│ ├── .gitignore
│ ├── .ignore
│ ├── ignore-splitting-0
│ ├── ignore-splitting-1
│ ├── ignore-splitting-2
│ ├── ignore-splitting-3
│ └── ignore-splitting-4
├── LICENSE
├── NvimApi/
│ ├── .gitignore
│ ├── LICENSE
│ ├── Package.swift
│ ├── README.md
│ ├── Sources/
│ │ └── NvimApi/
│ │ ├── Defs.swift
│ │ ├── MsgpackRpc.swift
│ │ ├── NvimApi.generated.swift
│ │ ├── NvimApi.swift
│ │ ├── NvimApiSync.generated.swift
│ │ └── NvimApiSync.swift
│ ├── Tests/
│ │ └── NvimApiTests/
│ │ ├── DictionaryExtensionTests.swift
│ │ ├── MsgpackRpcNeovimExample.swift
│ │ ├── NvimApiExample.swift
│ │ └── NvimApiSyncTest.swift
│ └── bin/
│ ├── api_generator_common.py
│ ├── generate_async_api_methods.py
│ ├── generate_sources.sh
│ ├── generate_sync_api_methods.py
│ └── requirements.txt
├── NvimView/
│ ├── .gitignore
│ ├── Package.swift
│ ├── README.md
│ ├── Sources/
│ │ └── NvimView/
│ │ ├── AttributesRunDrawer.swift
│ │ ├── CellAttributes.swift
│ │ ├── CellAttributesCollection.swift
│ │ ├── ColorUtils.swift
│ │ ├── Defs.swift
│ │ ├── FontUtils.swift
│ │ ├── Geometry.swift
│ │ ├── KeyUtils.swift
│ │ ├── MessagePackCommons.swift
│ │ ├── ModeInfo.swift
│ │ ├── NvimAutoCommandEvent.generated.swift
│ │ ├── NvimCursorModeShape.generated.swift
│ │ ├── NvimProcess.swift
│ │ ├── NvimView+Api.swift
│ │ ├── NvimView+Debug.swift
│ │ ├── NvimView+Dragging.swift
│ │ ├── NvimView+Draw.swift
│ │ ├── NvimView+Geometry.swift
│ │ ├── NvimView+Key.swift
│ │ ├── NvimView+MenuItems.swift
│ │ ├── NvimView+Mouse.swift
│ │ ├── NvimView+Objects.swift
│ │ ├── NvimView+RemoteOptions.swift
│ │ ├── NvimView+Resize.swift
│ │ ├── NvimView+TouchBar.swift
│ │ ├── NvimView+Types.swift
│ │ ├── NvimView+UiBridge.swift
│ │ ├── NvimView.swift
│ │ ├── Resources/
│ │ │ └── com.qvacua.NvimView.vim
│ │ ├── Runs.swift
│ │ ├── Typesetter.swift
│ │ └── UGrid.swift
│ ├── Support/
│ │ ├── DrawerDev/
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets/
│ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── Base.lproj/
│ │ │ │ └── MainMenu.xib
│ │ │ ├── Info.plist
│ │ │ ├── MyView.swift
│ │ │ └── NvimView.swift
│ │ ├── DrawerPerf/
│ │ │ ├── 0.json
│ │ │ ├── 1.json
│ │ │ ├── 2.json
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets/
│ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── Base.lproj/
│ │ │ │ └── MainMenu.xib
│ │ │ ├── FontTrait.swift
│ │ │ ├── Info.plist
│ │ │ ├── NvimView.swift
│ │ │ └── PerfTester.swift
│ │ ├── MinimalNvimViewDemo/
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets/
│ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── Base.lproj/
│ │ │ │ ├── Document.xib
│ │ │ │ └── MainMenu.xib
│ │ │ ├── Document.swift
│ │ │ └── Info.plist
│ │ └── NvimViewSupport.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── MinimalNvimViewDemo.xcscheme
│ └── Tests/
│ └── NvimViewTests/
│ ├── CellAttributesCollectionTest.swift
│ ├── NimbleCommons.swift
│ ├── TypesetterTest.swift
│ └── UGridTest.swift
├── README.md
├── Tabs/
│ ├── .gitignore
│ ├── Package.swift
│ ├── README.md
│ ├── Sources/
│ │ └── Tabs/
│ │ ├── DraggingSingleRowStackView.swift
│ │ ├── HorizontalOnlyScrollView.swift
│ │ ├── Tab.swift
│ │ ├── TabBar.swift
│ │ └── Theme.swift
│ └── Support/
│ ├── TabsSupport/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AccentColor.colorset/
│ │ │ │ └── Contents.json
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ └── MainMenu.xib
│ │ └── Info.plist
│ └── TabsSupport.xcodeproj/
│ └── project.pbxproj
├── VimR/
│ ├── Dev.xcconfig
│ ├── Release.xcconfig
│ ├── VimR/
│ │ ├── AdvancedPrefReducer.swift
│ │ ├── AdvencedPref.swift
│ │ ├── AppDelegate.swift
│ │ ├── AppDelegateReducer.swift
│ │ ├── AppKitCommons.swift
│ │ ├── AppearancePref.swift
│ │ ├── AppearancePrefReducer.swift
│ │ ├── Application.swift
│ │ ├── Assets.xcassets/
│ │ │ └── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ ├── Credits.rtf
│ │ │ ├── FileBrowserMenu.xib
│ │ │ ├── MainMenu.xib
│ │ │ ├── MainWindow.xib
│ │ │ ├── OpenQuicklyWindow.xib
│ │ │ └── PrefWindow.xib
│ │ ├── Bridge.h
│ │ ├── BufferList.swift
│ │ ├── BufferListReducer.swift
│ │ ├── Context.swift
│ │ ├── CoreDataStack.swift
│ │ ├── CssUtils.swift
│ │ ├── DefaultShortcuts.swift
│ │ ├── Defs.swift
│ │ ├── FileBrowser.swift
│ │ ├── FileBrowserReducer.swift
│ │ ├── FileItem+CoreDataClass.h
│ │ ├── FileItem+CoreDataClass.m
│ │ ├── FileMonitor.swift
│ │ ├── FileOutlineView.swift
│ │ ├── FoundationCommons.swift
│ │ ├── FuzzySearch.xcdatamodel/
│ │ │ └── contents
│ │ ├── FuzzySearchService.swift
│ │ ├── GeneralPref.swift
│ │ ├── GeneralPrefReducer.swift
│ │ ├── HtmlPreviewMiddleware.swift
│ │ ├── HtmlPreviewTool.swift
│ │ ├── HtmlPreviewToolReducer.swift
│ │ ├── HttpServerMiddleware.swift
│ │ ├── IgnoreService.swift
│ │ ├── ImageAndTextTableCell.swift
│ │ ├── Info.plist
│ │ ├── KeysPref.swift
│ │ ├── KeysPrefReducer.swift
│ │ ├── MainWindow+Actions.swift
│ │ ├── MainWindow+CustomTitle.swift
│ │ ├── MainWindow+Delegates.swift
│ │ ├── MainWindow+Types.swift
│ │ ├── MainWindow.swift
│ │ ├── MainWindowReducer.swift
│ │ ├── MarkdownPreviewMiddleware.swift
│ │ ├── MarkdownPreviewReducer.swift
│ │ ├── MarkdownTool.swift
│ │ ├── MarkdownToolReducer.swift
│ │ ├── OpenQuicklyFileViewRow.swift
│ │ ├── OpenQuicklyReducer.swift
│ │ ├── OpenQuicklyWindow.swift
│ │ ├── PrefMiddleware.swift
│ │ ├── PrefPane.swift
│ │ ├── PrefUtils.swift
│ │ ├── PrefWindow.swift
│ │ ├── PrefWindowReducer.swift
│ │ ├── Redux.swift
│ │ ├── Resources.swift
│ │ ├── RpcAppearanceReducer.swift
│ │ ├── RpcEvents.swift
│ │ ├── ScoredUrl.h
│ │ ├── ScoredUrl.m
│ │ ├── ShortcutItem.swift
│ │ ├── ShortcutService.swift
│ │ ├── ShortcutsPref.swift
│ │ ├── ShortcutsTableSubviews.swift
│ │ ├── States.swift
│ │ ├── Theme.swift
│ │ ├── ThemedTableSubviews.swift
│ │ ├── Throttler.swift
│ │ ├── ToolsPref.swift
│ │ ├── ToolsPrefReducer.swift
│ │ ├── Types.swift
│ │ ├── UiRoot.swift
│ │ ├── UiRootReducer.swift
│ │ ├── com.qvacua.VimR.vim
│ │ ├── macvim-file-icons/
│ │ │ ├── MacVim-applescript.icns
│ │ │ ├── MacVim-as.icns
│ │ │ ├── MacVim-asp.icns
│ │ │ ├── MacVim-bash.icns
│ │ │ ├── MacVim-bib.icns
│ │ │ ├── MacVim-bsh.icns
│ │ │ ├── MacVim-c.icns
│ │ │ ├── MacVim-cfg.icns
│ │ │ ├── MacVim-cgi.icns
│ │ │ ├── MacVim-cpp.icns
│ │ │ ├── MacVim-cs.icns
│ │ │ ├── MacVim-csfg.icns
│ │ │ ├── MacVim-css.icns
│ │ │ ├── MacVim-csv.icns
│ │ │ ├── MacVim-dtd.icns
│ │ │ ├── MacVim-dylan.icns
│ │ │ ├── MacVim-erl.icns
│ │ │ ├── MacVim-f.icns
│ │ │ ├── MacVim-fscript.icns
│ │ │ ├── MacVim-generic.icns
│ │ │ ├── MacVim-gtd.icns
│ │ │ ├── MacVim-h.icns
│ │ │ ├── MacVim-hs.icns
│ │ │ ├── MacVim-html.icns
│ │ │ ├── MacVim-ics.icns
│ │ │ ├── MacVim-inc.icns
│ │ │ ├── MacVim-ini.icns
│ │ │ ├── MacVim-io.icns
│ │ │ ├── MacVim-java.icns
│ │ │ ├── MacVim-js.icns
│ │ │ ├── MacVim-jsp.icns
│ │ │ ├── MacVim-lisp.icns
│ │ │ ├── MacVim-log.icns
│ │ │ ├── MacVim-m.icns
│ │ │ ├── MacVim-markdown.icns
│ │ │ ├── MacVim-mm.icns
│ │ │ ├── MacVim-patch.icns
│ │ │ ├── MacVim-perl.icns
│ │ │ ├── MacVim-php.icns
│ │ │ ├── MacVim-plist.icns
│ │ │ ├── MacVim-properties.icns
│ │ │ ├── MacVim-ps.icns
│ │ │ ├── MacVim-py.icns
│ │ │ ├── MacVim-rb.icns
│ │ │ ├── MacVim-rst.icns
│ │ │ ├── MacVim-sch.icns
│ │ │ ├── MacVim-sql.icns
│ │ │ ├── MacVim-tcl.icns
│ │ │ ├── MacVim-tex.icns
│ │ │ ├── MacVim-tsv.icns
│ │ │ ├── MacVim-txt.icns
│ │ │ ├── MacVim-vb.icns
│ │ │ ├── MacVim-vba.icns
│ │ │ ├── MacVim-vcf.icns
│ │ │ ├── MacVim-vim.icns
│ │ │ ├── MacVim-wiki.icns
│ │ │ ├── MacVim-xml.icns
│ │ │ ├── MacVim-xsl.icns
│ │ │ └── MacVim-yaml.icns
│ │ ├── markdown/
│ │ │ ├── color-overrides.css
│ │ │ ├── github-markdown.css
│ │ │ └── template.html
│ │ ├── preview/
│ │ │ ├── base.css
│ │ │ ├── empty.html
│ │ │ ├── error.html
│ │ │ ├── save-first.html
│ │ │ └── select-first.html
│ │ └── vimr
│ ├── VimR.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── VimR.xcscheme
│ └── VimRTests/
│ ├── IgnoreServiceTest.swift
│ ├── Info.plist
│ └── Resources/
│ └── ignore-service-test/
│ ├── .gitignore
│ └── a/
│ ├── .gitignore
│ └── aa/
│ └── aaa/
│ └── .gitignore
├── VimR.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ ├── IDEWorkspaceChecks.plist
│ └── WorkspaceSettings.xcsettings
├── Workspace/
│ ├── .gitignore
│ ├── Package.swift
│ ├── README.md
│ └── Sources/
│ └── Workspace/
│ ├── InnterToolBar.swift
│ ├── ProxyWorkspaceBar.swift
│ ├── Workspace.swift
│ ├── WorkspaceBar.swift
│ ├── WorkspaceTool.swift
│ └── WorkspaceToolButton.swift
├── appcast.xml
├── appcast_snapshot.xml
├── bin/
│ ├── .python-version
│ ├── README.md
│ ├── build_jenkins.sh
│ ├── build_nightly_jenkins.sh
│ ├── build_nvimserver.sh
│ ├── build_release.sh
│ ├── build_vimr.sh
│ ├── generate_autocmds.py
│ ├── generate_cursor_shape.py
│ ├── generate_sources.sh
│ ├── neovim/
│ │ ├── bin/
│ │ │ ├── .gitignore
│ │ │ ├── build_neovim.sh
│ │ │ ├── build_neovim_for_dev.sh
│ │ │ └── build_universal_neovim.sh
│ │ └── resources/
│ │ ├── NvimServer.entitlements
│ │ └── buildInfo.json
│ ├── notarize_vimr.sh
│ ├── pre-commit.py
│ ├── publish_release.sh
│ ├── requirements.txt
│ ├── set_appcast.py
│ ├── set_new_versions.sh
│ ├── setup_markdown_css.sh
│ ├── shelly.py
│ └── sign_vimr.sh
├── ci/
│ ├── README.md
│ └── create_build_job.groovy
├── docs/
│ └── notes-on-cocoa-text-input.md
└── resources/
├── appcast_template.xml
├── autocmds.template.swift
├── cursor_shape.template.swift
└── release-notes.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: [qvacua]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
================================================
FILE: .github/workflows/build-universal-neovim.yml
================================================
name: 'Universal Neovim'
on:
push:
tags:
# example: neovim-v0.10.0-20240601.102525
- neovim-v[0-9]+.[0-9]+.[0-9]+-*
jobs:
build-x86:
runs-on: macos-15-intel
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: true
- run: brew bundle
- run: clean=true ./bin/neovim/bin/build_neovim.sh
- uses: actions/upload-artifact@v4
with:
name: nvim-macos-x86_64
path: Neovim/build/nvim-macos-x86_64.tar.gz
retention-days: 1
build-arm:
runs-on: macos-15
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: true
- run: brew bundle
- run: clean=true ./bin/neovim/bin/build_neovim.sh
- uses: actions/upload-artifact@v4
with:
name: nvim-macos-arm64
path: Neovim/build/nvim-macos-arm64.tar.gz
retention-days: 1
publish:
needs: [build-x86, build-arm]
runs-on: macos-15
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/download-artifact@v4
- run: brew bundle
- run: |
mv nvim-macos-*/* .
rm -r nvim-macos-x86_64 nvim-macos-arm64
- run: ./bin/neovim/bin/build_universal_neovim.sh
- run: |
gh release create ${{ github.ref_name }} \
--prerelease \
--title "Universal ${{ github.ref_name }}" \
--notes "Neovim universal build with libintl, not signed." \
--target ${{ github.sha }} \
nvim-macos-x86_64.tar.gz nvim-macos-arm64.tar.gz nvim-macos-universal.tar.bz
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .gitignore
================================================
.DS_Store
.idea/
*.ipr
*.iws
*.iml
*.pbxuser
xcuserdata
DerivedData
*.xcuserstate
.vscode/
.swiftpm
Package.resolved
build/
.build/
.DerivedData/
================================================
FILE: .gitmodules
================================================
[submodule "Neovim"]
path = Neovim
url = https://github.com/neovim/neovim.git
================================================
FILE: .swiftformat
================================================
--swiftversion 6.0
--exclude **/*.template.swift,.build,.swiftpm
--indent 2
--maxwidth 100
--self insert
--wraparguments before-first
--ranges no-space
--strip-unused-args unnamed-only
--ifdef no-indent
--import-grouping testable-bottom # sortedImports
--trailing-commas always
--rules sortImports
--rules redundantSelf
--rules indent
--rules wraparguments
--rules trailingCommas
--rules typeSugar
================================================
FILE: .swiftlint.yml
================================================
disabled_rules:
- trailing_comma
- identifier_name
- function_parameter_count
- file_length
- no_unchecked_sendable
- opening_brace
- statement_position
- function_body_length
- duplicate_enum_cases
- closure_parameter_position
- nesting
- type_body_length
- line_length
- cyclomatic_complexity
- large_tuple
- trailing_whitespace
- type_name
excluded:
- "**/build"
- "**/.build"
- "**/.swiftpm"
indentation: 2
custom_rules:
no_objcMembers:
name: "@objcMembers"
regex: "@objcMembers"
message: "Explicitly use @objc on each member you want to expose to Objective-C"
severity: error
no_direct_standard_out_logs:
name: "Writing log messages directly to standard out is disallowed"
regex: "(\\bprint|\\bdebugPrint|\\bdump|Swift\\.print|Swift\\.debugPrint|Swift\\.dump|_printChanges)\\s*\\("
match_kinds:
- identifier
message: "Don't commit `print(…)`, `debugPrint(…)`, `dump(…)`, or `_printChanges()` as they write to standard out in release. Either log to a dedicated logging system or silence this warning in debug-only scenarios explicitly using `// swiftlint:disable:next no_direct_standard_out_logs`"
severity: error
no_file_literal:
name: "#file is disallowed"
regex: "(\\b#file\\b)"
match_kinds:
- identifier
message: "Instead of #file, use #fileID"
severity: error
no_filepath_literal:
name: "#filePath is disallowed"
regex: "(\\b#filePath\\b)"
match_kinds:
- identifier
message: "Instead of #filePath, use #fileID."
severity: error
no_unchecked_sendable:
name: "`@unchecked Sendable` is discouraged."
regex: "@unchecked Sendable"
match_kinds:
- attribute.builtin
- typeidentifier
message: "Instead of using `@unchecked Sendable`, consider a safe alternative like a standard `Sendable` conformance or using `@preconcurrency import`. If you really must use `@unchecked Sendable`, you can add a `// swiftlint:disable:next no_unchecked_sendable` annotation with an explanation for how we know the type is thread-safe, and why we have to use @unchecked Sendable instead of Sendable. More explanation and suggested safe alternatives are available at https://github.com/airbnb/swift#unchecked-sendable."
severity: error
================================================
FILE: Brewfile
================================================
brew 'coreutils'
brew 'gnu-sed'
brew 'libtool'
brew 'automake'
brew 'cmake'
brew 'pkg-config'
brew 'gettext'
brew 'ninja'
brew 'coreutils'
brew 'python3'
================================================
FILE: Commons/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
================================================
FILE: Commons/Package.swift
================================================
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "Commons",
platforms: [.macOS(.v14)],
products: [
.library(name: "Commons", targets: ["Commons", "CommonsObjC"]),
],
dependencies: [
.package(url: "https://github.com/Quick/Nimble", from: "14.0.0"),
.package(url: "https://github.com/SimplyDanny/SwiftLintPlugins", from: "0.62.2"),
],
targets: [
.target(
name: "Commons",
dependencies: [],
plugins: [.plugin(name: "SwiftLintBuildToolPlugin", package: "SwiftLintPlugins")]
),
.target(name: "CommonsObjC", dependencies: []),
.testTarget(
name: "CommonsTests",
dependencies: ["Commons", "Nimble"],
resources: [
.copy("Resources"),
]
),
]
)
================================================
FILE: Commons/README.md
================================================
# Commons
A description of this package.
================================================
FILE: Commons/Sources/Commons/AppKitCommons.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import AppKit
public extension NSAttributedString {
func draw(at point: CGPoint, angle: CGFloat) {
var translation = AffineTransform.identity
var rotation = AffineTransform.identity
translation.translate(x: point.x, y: point.y)
rotation.rotate(byRadians: angle)
(translation as NSAffineTransform).concat()
(rotation as NSAffineTransform).concat()
self.draw(at: CGPoint.zero)
rotation.invert()
translation.invert()
(rotation as NSAffineTransform).concat()
(translation as NSAffineTransform).concat()
}
var wholeRange: NSRange { NSRange(location: 0, length: self.length) }
}
public extension NSColor {
static var random: NSColor {
NSColor(
calibratedRed: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1.0
)
}
var int: Int {
if let color = self.usingColorSpace(.sRGB) {
let a = Int(color.alphaComponent * 255)
let r = Int(color.redComponent * 255)
let g = Int(color.greenComponent * 255)
let b = Int(color.blueComponent * 255)
return a << 24 | r << 16 | g << 8 | b
} else {
return 0
}
}
var hex: String { String(String(format: "%06X", self.int).suffix(6)) }
convenience init(rgb: Int) {
// @formatter:off
let red = ((rgb >> 16) & 0xFF).cgf / 255.0
let green = ((rgb >> 8) & 0xFF).cgf / 255.0
let blue = (rgb & 0xFF).cgf / 255.0
// @formatter:on
self.init(srgbRed: red, green: green, blue: blue, alpha: 1.0)
}
convenience init?(hex: String) {
guard hex.count == 6,
let uint64 = Scanner(string: hex).scanUInt64(representation: .hexadecimal)
else { return nil }
let result = UInt32(uint64)
let r = (result & 0xFF0000) >> 16
let g = (result & 0x00FF00) >> 8
let b = (result & 0x0000FF)
self.init(srgbRed: r.cgf / 255, green: g.cgf / 255, blue: b.cgf / 255, alpha: 1)
}
func brightening(by factor: CGFloat) -> NSColor {
guard let color = self.usingColorSpace(.sRGB) else { return self }
let h = color.hueComponent
let s = color.saturationComponent
let b = color.brightnessComponent
let a = color.alphaComponent
return NSColor(hue: h, saturation: s, brightness: b * factor, alpha: a)
}
}
public extension NSImage {
func tinting(with color: NSColor) -> NSImage {
// swiftlint:disable force_cast
// Copy should be safe to force cast.
let result = self.copy() as! NSImage
// swiftlint:enable force_cast
result.lockFocus()
color.set()
CGRect(origin: .zero, size: self.size).fill(using: .sourceAtop)
result.unlockFocus()
return result
}
}
public extension NSButton {
var boolState: Bool {
get { self.state == .on ? true : false }
set { self.state = newValue ? .on : .off }
}
}
public extension NSMenuItem {
var boolState: Bool {
get { self.state == .on ? true : false }
set { self.state = newValue ? .on : .off }
}
}
public extension NSView {
func removeAllSubviews() { self.subviews.forEach { $0.removeFromSuperview() } }
func removeAllConstraints() { self.removeConstraints(self.constraints) }
func beFirstResponder() { self.window?.makeFirstResponder(self) }
/// - Returns: Rects currently being drawn
/// - Warning: Call only in drawRect()
func rectsBeingDrawn() -> [CGRect] {
var rectsPtr: UnsafePointer<CGRect>?
var count = 0
self.getRectsBeingDrawn(&rectsPtr, count: &count)
return Array(UnsafeBufferPointer(start: rectsPtr, count: count))
}
}
public extension NSEvent.ModifierFlags {
// Values are from
// https://github.com/SFML/SFML/blob/master/src/SFML/Window/OSX/SFKeyboardModifiersHelper.mm
static let rightShift = NSEvent.ModifierFlags(rawValue: 0x020004)
static let leftShift = NSEvent.ModifierFlags(rawValue: 0x020002)
static let rightCommand = NSEvent.ModifierFlags(rawValue: 0x100010)
static let leftCommand = NSEvent.ModifierFlags(rawValue: 0x100008)
static let rightOption = NSEvent.ModifierFlags(rawValue: 0x080040)
static let leftOption = NSEvent.ModifierFlags(rawValue: 0x080020)
static let rightControl = NSEvent.ModifierFlags(rawValue: 0x042000)
static let leftControl = NSEvent.ModifierFlags(rawValue: 0x040001)
}
================================================
FILE: Commons/Sources/Commons/ConditionVariable.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
public final class ConditionVariable: Sendable {
private(set) nonisolated(unsafe) var posted: Bool
public init(posted: Bool = false) {
self.posted = posted
}
public func wait(for seconds: TimeInterval, then fn: (() -> Void)? = nil) {
self.condition.lock()
defer { self.condition.unlock() }
while !self.posted {
self.condition.wait(until: Date(timeIntervalSinceNow: seconds))
self.posted = true
}
fn?()
}
public func broadcast(then fn: (() -> Void)? = nil) {
self.condition.lock()
defer { self.condition.unlock() }
self.posted = true
self.condition.broadcast()
fn?()
}
private let condition = NSCondition()
}
================================================
FILE: Commons/Sources/Commons/CoreCommons.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
public extension CFRange {
static let zero = CFRange(location: 0, length: 0)
}
public extension CGSize {
func scaling(_ factor: CGFloat) -> CGSize {
CGSize(width: self.width * factor, height: self.height * factor)
}
}
================================================
FILE: Commons/Sources/Commons/Defs.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
enum Defs {
static let loggerSubsystem = "com.qvacua.Commons"
enum LoggerCategory {
static let general = "general"
}
}
let dlog = DevLogger.shared
================================================
FILE: Commons/Sources/Commons/FifoCache.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
import os
public final class ThreadSafeFifoCache<Key: Hashable, Value>: @unchecked Sendable {
public init(count: Int) {
self.count = count
self.keyWriteIndex = 0
self.keys = Array(repeating: nil, count: count)
self.storage = Dictionary(minimumCapacity: count)
}
public func set(_ value: Value, forKey key: Key) {
self.lock.lock()
if let keyToDel = self.keys[self.keyWriteIndex] { self.storage.removeValue(forKey: keyToDel) }
self.keys[self.keyWriteIndex] = key
self.storage[key] = value
self.keyWriteIndex = (self.keyWriteIndex + 1) % self.count
self.lock.unlock()
}
public func valueForKey(_ key: Key) -> Value? {
self.lock.lock()
let value = self.storage[key]
self.lock.unlock()
return value
}
public func clear() {
self.lock.lock()
self.keys = Array(repeating: nil, count: self.count)
self.storage.removeAll(keepingCapacity: true)
self.lock.unlock()
}
private let count: Int
private var keys: [Key?]
private var keyWriteIndex: Int
private var storage: [Key: Value]
private let lock = OSAllocatedUnfairLock()
}
public final class FifoCache<Key: Hashable, Value> {
public init(count: Int) {
self.count = count
self.keyWriteIndex = 0
self.keys = Array(repeating: nil, count: count)
self.storage = Dictionary(minimumCapacity: count)
}
public func set(_ value: Value, forKey key: Key) {
if let keyToDel = self.keys[self.keyWriteIndex] { self.storage.removeValue(forKey: keyToDel) }
self.keys[self.keyWriteIndex] = key
self.storage[key] = value
self.keyWriteIndex = (self.keyWriteIndex + 1) % self.count
}
public func valueForKey(_ key: Key) -> Value? { self.storage[key] }
public func clear() {
self.keys = Array(repeating: nil, count: self.count)
self.storage.removeAll(keepingCapacity: true)
}
private let count: Int
private var keys: [Key?]
private var keyWriteIndex: Int
private var storage: [Key: Value]
}
================================================
FILE: Commons/Sources/Commons/FileUtils.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import AppKit
import Cocoa
import UniformTypeIdentifiers
// icon(forFile:) is thread-safe: https://developer.apple.com/documentation/appkit/nsworkspace/icon(forfile:)
// icon(for:) probably is thread-safe
private nonisolated(unsafe) let workspace = NSWorkspace.shared
// NSCache is thread-safe: https://developer.apple.com/documentation/foundation/nscache#overview
private nonisolated(unsafe) let iconsCache = NSCache<NSURL, NSImage>()
// FileManager is thread-safe:
// https://developer.apple.com/documentation/foundation/filemanager#1651181
private nonisolated(unsafe) let fm = FileManager.default
public final class FileUtils {
private static let keysToGet: [URLResourceKey] = [
.isRegularFileKey,
.isDirectoryKey,
.isPackageKey,
.isHiddenKey,
]
private static let scanOptions: FileManager.DirectoryEnumerationOptions = [
.skipsSubdirectoryDescendants,
.skipsPackageDescendants,
]
public static let userHomeUrl = URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)
public static func tempDir() -> URL {
URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
}
public static func directDescendants(of url: URL) -> [URL] {
guard let childUrls = try? fm.contentsOfDirectory(
at: url, includingPropertiesForKeys: self.keysToGet, options: self.scanOptions
) else { return [] }
return childUrls
}
public static func fileExists(at url: URL) -> Bool {
guard url.isFileURL else { return false }
let path = url.path
return fm.fileExists(atPath: path)
}
public static func commonParent(of urls: [URL]) -> URL {
guard urls.count > 0 else { return URL(fileURLWithPath: "/", isDirectory: true) }
let pathComps = urls.map { $0.deletingLastPathComponent().pathComponents }
let min = pathComps.map(\.count).min()!
let pathCompsOnlyMin = pathComps.map { $0[0..<min] }
let commonIdx = (0..<min).reversed().reduce(min - 1) { result, idx in
if Set(pathCompsOnlyMin.map { $0[idx] }).count > 1 { idx - 1 }
else { result }
}
let result = pathCompsOnlyMin[0]
let possibleParent = NSURL.fileURL(withPathComponents: Array(result[0...commonIdx]))!
return possibleParent.hasDirectoryPath ? possibleParent : possibleParent.parent
}
public static func icon(forType type: String) -> NSImage { workspace
.icon(for: UTType(type) ?? UTType.text)
}
public static func icon(forUrl url: URL) -> NSImage? {
if let cached = iconsCache.object(forKey: url as NSURL) { return cached }
let path = url.path
let icon = workspace.icon(forFile: path)
icon.size = CGSize(width: 16, height: 16)
iconsCache.setObject(icon, forKey: url as NSURL)
return icon
}
}
================================================
FILE: Commons/Sources/Commons/FoundationCommons.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
import os
public extension Array where Element: Hashable {
// From https://stackoverflow.com/a/46354989
func uniqued() -> [Element] {
var seen = Set<Element>()
return self.filter { seen.insert($0).inserted }
}
}
public extension Array {
func data() -> Data { self.withUnsafeBufferPointer(Data.init) }
}
public extension RandomAccessCollection where Index == Int {
func groupedRanges(with marker: (Element) -> some Equatable) -> [ClosedRange<Index>] {
guard !self.isEmpty else { return [] }
var result = [ClosedRange<Index>]()
result.reserveCapacity(self.count / 2)
var start = self.startIndex
var lastMarker = marker(self[start])
for i in self.indices.dropFirst() {
let currentMarker = marker(self[i])
if lastMarker != currentMarker {
result.append(start...i - 1)
start = i
lastMarker = currentMarker
}
}
result.append(start...self.endIndex - 1)
return result
}
}
public extension NSRange {
static let notFound = NSRange(location: NSNotFound, length: 0)
var inclusiveEndIndex: Int { self.location + self.length - 1 }
}
public extension URL {
func isParent(of url: URL) -> Bool {
guard self.isFileURL, url.isFileURL else { return false }
let myPathComps = self.pathComponents
let targetPathComps = url.pathComponents
guard targetPathComps.count == myPathComps.count + 1 else { return false }
return Array(targetPathComps[0..<myPathComps.count]) == myPathComps
}
func isAncestor(of url: URL) -> Bool {
guard self.isFileURL, url.isFileURL else { return false }
let myPathComps = self.pathComponents
let targetPathComps = url.pathComponents
guard targetPathComps.count > myPathComps.count else { return false }
return Array(targetPathComps[0..<myPathComps.count]) == myPathComps
}
func isContained(in parentUrl: URL) -> Bool {
if parentUrl == self { return false }
let pathComps = self.pathComponents
let parentPathComps = parentUrl.pathComponents
guard pathComps.count > parentPathComps.count else { return false }
guard Array(pathComps[0..<parentPathComps.endIndex]) == parentPathComps else { return false }
return true
}
var parent: URL {
if self.path == "/" { return self }
return self.deletingLastPathComponent()
}
var shellEscapedPath: String { self.path.shellEscapedPath }
var isRegularFile: Bool {
(try? self.resourceValues(forKeys: [.isRegularFileKey]))?.isRegularFile ?? false
}
var isHidden: Bool { (try? self.resourceValues(forKeys: [.isHiddenKey]))?.isHidden ?? false }
var isPackage: Bool { (try? self.resourceValues(forKeys: [.isPackageKey]))?.isPackage ?? false }
}
================================================
FILE: Commons/Sources/Commons/LoggerCommons.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
import os
public extension Logger {
func error(
file: String = #file,
function: String = #function,
line: Int = #line,
_ msg: @autoclosure () -> some Any
) {
let message = "[\((file as NSString).lastPathComponent) - \(function):\(line)] \(msg())"
self.log(level: .error, "\(message)")
}
func fault(
file: String = #file,
function: String = #function,
line: Int = #line,
_ msg: @autoclosure () -> some Any
) {
let message = "[\((file as NSString).lastPathComponent) - \(function):\(line)] \(msg())"
self.log(level: .fault, "\(message)")
}
}
public struct DevLogger: Sendable {
public static let shared = DevLogger(mode: .file)
public enum Mode {
case os
case file
case noop
}
private let appender: LogAppender
public init(mode: Mode) {
let subsystem = Bundle.main.bundleIdentifier ?? "app-\(UUID().uuidString)"
let category = "development"
#if DEBUG || TRACE
switch mode {
case .os:
self.appender = OsAppender(subsystem: subsystem, category: category)
case .file:
self.appender = FileAppender(subsystem: subsystem, category: category) ?? OsAppender(
subsystem: subsystem,
category: category
)
case .noop:
self.appender = NoopAppender()
}
#else
self.appender = NoopAppender()
#endif
}
public func debug(
file: String = #file,
function: String = #function,
line: Int = #line
) {
#if DEBUG
self.appender.debug(file: file, function: function, line: line, "MARK")
#endif
}
public func debug(
file: String = #file,
function: String = #function,
line: Int = #line,
_ msg: @autoclosure () -> some Any
) {
#if DEBUG
self.appender.debug(file: file, function: function, line: line, "\(msg())")
#endif
}
public func trace(
file: String = #file,
function: String = #function,
line: Int = #line,
_ msg: @autoclosure () -> some Any
) {
#if TRACE
self.appender.trace(file: file, function: function, line: line, "\(msg())")
#endif
}
protocol LogAppender: Sendable {
func debug(file: String, function: String, line: Int, _ msg: String)
func trace(file: String, function: String, line: Int, _ msg: String)
}
struct NoopAppender: LogAppender {
func debug(file: String, function: String, line: Int, _: String) {}
func trace(file: String, function: String, line: Int, _: String) {}
}
// We sync using a DispatchQueue
class FileAppender: LogAppender, @unchecked Sendable {
static let fileSizeLimit = 1024 * 1024 * 10 // 10MB
private let logger: Logger
private let queue: DispatchQueue
private let logDir: URL
private let dateStr: String
private var logFileNumber = 0
private var fileHandle: FileHandle
private var estimatedFileSize = UInt64(0)
private let timeFormatter = DateFormatter()
init?(subsystem: String, category: String) {
self.logger = Logger(subsystem: subsystem, category: "info")
self.queue = DispatchQueue(label: "\(subsystem).\(category)-queue", qos: .utility)
let formatter = DateFormatter()
formatter.dateFormat = "yyyyMMdd.HHmmss"
self.dateStr = formatter.string(from: Date())
self.timeFormatter.dateFormat = "HH:mm:ss.SSS"
let tempDir = FileManager.default.temporaryDirectory
self.logDir = tempDir.appendingPathComponent("\(subsystem).\(category)")
do {
try FileManager.default.createDirectory(at: self.logDir, withIntermediateDirectories: true)
let logFile = self.logDir
.appendingPathComponent("\(self.dateStr)-\(self.logFileNumber).log")
if !FileManager.default.fileExists(atPath: logFile.path) {
FileManager.default.createFile(atPath: logFile.path, contents: nil)
}
self.fileHandle = try FileHandle(forWritingTo: logFile)
self.estimatedFileSize = try self.fileHandle.seekToEnd()
self.logger.info("Logging to \(logFile)")
} catch {
self.logger.error("Error creating FileAppender!")
return nil
}
}
deinit {
do {
try self.fileHandle.close()
} catch {
self.logger.error("Could not close file handle: \(error)")
}
}
// Only call when inside the queue
private func checkFileSizeAndRotate() {
guard self.estimatedFileSize >= Self.fileSizeLimit else {
return
}
self.logFileNumber += 1
let logFile = self.logDir
.appendingPathComponent("\(self.dateStr)-\(self.logFileNumber).log")
if !FileManager.default.fileExists(atPath: logFile.path) {
FileManager.default.createFile(atPath: logFile.path, contents: nil)
}
do {
let newFileHandle = try FileHandle(forWritingTo: logFile)
self.estimatedFileSize = try newFileHandle.seekToEnd()
try self.fileHandle.close()
self.fileHandle = newFileHandle
self.logger.info("Rotated: logging to \(logFile)")
} catch {
self.logger
.error("""
Rotation to \(logFile) failed: \(error).
Logging to the current log file, maybe rotation will succeed when logging next.
""")
}
}
private func write(
file f: String,
function fn: String,
line l: Int,
prefix: String,
_ msg: String
) {
let now = Date()
self.queue.async {
let t = self.timeFormatter.string(from: now)
let str = "\(t) [\(prefix)] [\((f as NSString).lastPathComponent) - \(fn):\(l)] \(msg)\n"
let data = Data(str.utf8)
do {
try self.fileHandle.write(contentsOf: data)
self.estimatedFileSize += UInt64(data.count)
} catch {
self.logger.error("""
Couldn't log to file: err: \(error)
Msg: \(str.dropLast())
""")
return
}
self.checkFileSizeAndRotate()
}
}
func debug(file: String, function: String, line: Int, _ msg: String) {
self.write(file: file, function: function, line: line, prefix: "DEBUG", msg)
}
func trace(file: String, function: String, line: Int, _ msg: String) {
self.write(file: file, function: function, line: line, prefix: "TRACE", msg)
}
}
struct OsAppender: LogAppender {
private let logger: Logger
init(subsystem: String, category: String) {
self.logger = Logger(subsystem: subsystem, category: category)
}
func debug(file: String, function: String, line: Int, _ msg: String) {
self.logger.log(
level: .debug,
"[DEBUG] [\((file as NSString).lastPathComponent) - \(function):\(line)] \(msg)"
)
}
func trace(file: String, function: String, line: Int, _ msg: String) {
self.logger.log(
level: .debug,
"[TRACE] [\((file as NSString).lastPathComponent) - \(function):\(line)] \(msg)"
)
}
}
}
================================================
FILE: Commons/Sources/Commons/ProcessUtils.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
import os
public enum ProcessUtils {
public static func loginShell() -> URL {
URL(fileURLWithPath: ProcessInfo.processInfo.environment["SHELL"] ?? "/bin/bash")
}
public static func execProcessViaLoginShell(
cmd: String,
cwd: URL,
envs: [String: String],
interactive: Bool,
qos: QualityOfService
) -> Process? {
let shellUrl = Self.loginShell()
let shellName = shellUrl.lastPathComponent
var shellArgs = [String]()
if shellName != "tcsh" { shellArgs.append("-l") }
if interactive { shellArgs.append("-i") }
dlog.debug("Using \(shellUrl) with \(shellArgs)")
let stdin = Pipe()
let process = Process()
process.environment = envs
process.standardInput = stdin
process.standardOutput = Pipe()
process.standardError = Pipe()
process.currentDirectoryPath = cwd.path
process.launchPath = shellUrl.path
process.arguments = shellArgs
process.qualityOfService = qos
dlog.debug("Launched shell")
do { try process.run() }
catch { return nil }
dlog.debug("exec \(cmd)")
let cmd = "exec \(cmd)"
guard let cmdData = cmd.data(using: .utf8) else { return nil }
let writeHandle = stdin.fileHandleForWriting
writeHandle.write(cmdData)
writeHandle.closeFile()
return process
}
public static func envVars(
of shellPath: URL,
usingInteractiveMode: Bool
) -> [String: String] {
let shellName = shellPath.lastPathComponent
var shellArgs = [String]()
if shellName != "tcsh" {
shellArgs.append("-l")
}
if usingInteractiveMode {
shellArgs.append("-i")
}
let marker = UUID().uuidString
shellArgs.append(contentsOf: ["-c", "echo \(marker) && env"])
let outputPipe = Pipe()
let errorPipe = Pipe()
let process = Process()
process.launchPath = shellPath.path
process.arguments = shellArgs
process.standardOutput = outputPipe
process.standardError = errorPipe
process.currentDirectoryPath = NSHomeDirectory()
process.launch()
let readHandle = outputPipe.fileHandleForReading
guard let output = String(
data: readHandle.readDataToEndOfFile(), encoding: .utf8
) else {
Self.logger.error("No output; returning empty ENVs.")
return [:]
}
readHandle.closeFile()
process.terminate()
process.waitUntilExit()
guard let range = output.range(of: marker) else {
Self.logger.error("Marker not found; returning empty ENVs.")
return [:]
}
return output[range.upperBound...]
.trimmingCharacters(in: .whitespacesAndNewlines)
.split(separator: "\n")
.reduce(into: [:]) { result, entry in
let split = entry
.split(separator: "=", maxSplits: 1, omittingEmptySubsequences: false)
.map { String($0) }
guard split.count > 1 else { return }
result[split[0]] = split[1]
}
}
private static let logger = Logger(
subsystem: Defs.loggerSubsystem,
category: Defs.LoggerCategory.general
)
}
================================================
FILE: Commons/Sources/Commons/SwiftCommons.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
public func identity<T>(_ input: T) -> T { input }
public extension FixedWidthInteger {
@inlinable
@inline(__always)
var cgf: CGFloat { CGFloat(self) }
}
public extension String {
func without(prefix: String) -> String {
guard self.hasPrefix(prefix) else { return self }
let idx = self.index(self.startIndex, offsetBy: prefix.count)
return String(self[idx..<self.endIndex])
}
// From https://stackoverflow.com/a/56391610
@inlinable
@inline(__always)
var fullRange: NSRange { NSRange(self.startIndex..., in: self) }
// From https://stackoverflow.com/a/55560988
var shellEscapedPath: String {
shellEscapeRegex.stringByReplacingMatches(
in: self,
range: self.fullRange,
withTemplate: "\\\\$1"
)
}
}
public extension Array where Element: Equatable {
/**
Returns an array where elements of `elements` contained in the array are substituted
by elements of `elements`. This is useful when you need pointer equality
rather than `Equatable`-equality like in `NSOutlineView`.
If an element of `elements` is not contained in the array, it's ignored.
*/
func substituting(elements: [Element]) -> [Element] {
let elementsInArray = elements.filter { self.contains($0) }
let indices = elementsInArray.compactMap { self.firstIndex(of: $0) }
var result = self
indices.enumerated().forEach { result[$0.1] = elementsInArray[$0.0] }
return result
}
}
public extension Array where Element: Hashable {
func toDict<V>(by mapper: @escaping (Element) -> V) -> [Element: V] {
var result = [Element: V](minimumCapacity: self.count)
self.forEach { result[$0] = mapper($0) }
return result
}
// From https://stackoverflow.com/a/46354989
func uniqueing() -> [Element] {
var seen = Set<Element>()
return filter { seen.insert($0).inserted }
}
}
func tuplesToDict<K: Hashable, V, S: Sequence>(_ sequence: S)
-> [K: V] where S.Iterator.Element == (K, V)
{
var result = [K: V](minimumCapacity: sequence.underestimatedCount)
for (key, value) in sequence {
result[key] = value
}
return result
}
public extension Dictionary {
func mapToDict<K, V>(_ transform: ((key: Key, value: Value)) throws -> (K, V)) rethrows
-> [K: V]
{
let array = try self.map(transform)
return tuplesToDict(array)
}
func flatMapToDict<K, V>(_ transform: ((key: Key, value: Value)) throws -> (K, V)?) rethrows
-> [K: V]
{
let array = try self.compactMap(transform)
return tuplesToDict(array)
}
}
// From https://stackoverflow.com/a/55560988
// We know that the regex is valid.
// swiftlint:disable:next force_try
private let shellEscapeRegex = try! NSRegularExpression(
pattern: "([ !\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\,\\:\\;\\<\\=\\>\\?\\[\\]\\`\\{\\|\\}\\~])"
)
================================================
FILE: Commons/Sources/CommonsObjC/NetUtils.m
================================================
/**
* Greg Omelaenko - http://omelaen.co
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import "NetUtils.h"
#import <os/log.h>
#import <sys/socket.h>
#import <netinet/in.h>
static os_log_t logger = NULL;
@implementation NetUtils
+ (void)initialize {
if (self == [NetUtils class]) {
logger = os_log_create("com.qvacua.VimR", "general");
}
}
// from https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/UsingSocketsandSocketStreams.html#//apple_ref/doc/uid/CH73-SW9
// and http://stackoverflow.com/a/20850182/6939513
// slightly modified
+ (in_port_t)openPort {
const int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
os_log_error(logger, "Could not open socket");
return 0;
}
struct sockaddr_in sin = {
.sin_len = sizeof(sin),
.sin_family = AF_INET,
.sin_port = htons(0),
.sin_addr.s_addr = INADDR_ANY
};
if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
if (errno == EADDRINUSE) {
os_log_error(logger, "the port is not available.");
} else {
os_log_error(
logger,
"could not bind to process (%{public}d) %{public}s",
errno,
strerror(errno)
);
}
close(sock);
return 0;
}
socklen_t len = sizeof(sin);
if (getsockname(sock, (struct sockaddr *) &sin, &len) == -1) {
os_log_error(logger, "getsockname failed.");
close(sock);
return 0;
}
const in_port_t result = ntohs(sin.sin_port);
if (close(sock) < 0) {
os_log_error(logger, "socket did not close: %{public}s", strerror(errno));
return 0;
}
return result;
}
@end
================================================
FILE: Commons/Sources/CommonsObjC/include/NetUtils.h
================================================
/**
* Greg Omelaenko - http://omelaen.co
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import <Foundation/Foundation.h>
@interface NetUtils : NSObject
+ (in_port_t)openPort;
@end
================================================
FILE: Commons/Support/CommonsSupport.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
4B7FBFFB24EC936C002D12A1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7FBFFA24EC936C002D12A1 /* AppDelegate.swift */; };
4B7FBFFD24EC936E002D12A1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4B7FBFFC24EC936E002D12A1 /* Assets.xcassets */; };
4B7FC00024EC936E002D12A1 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B7FBFFE24EC936E002D12A1 /* MainMenu.xib */; };
4B7FC00824EC9425002D12A1 /* Commons in Frameworks */ = {isa = PBXBuildFile; productRef = 4B7FC00724EC9425002D12A1 /* Commons */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
4B7FBFF824EC936C002D12A1 /* EnvVarTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EnvVarTest.app; sourceTree = BUILT_PRODUCTS_DIR; };
4B7FBFFA24EC936C002D12A1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
4B7FBFFC24EC936E002D12A1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
4B7FBFFF24EC936E002D12A1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
4B7FC00124EC936E002D12A1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
4B7FBFF524EC936C002D12A1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4B7FC00824EC9425002D12A1 /* Commons in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
4B7FBFDA24EC92F2002D12A1 = {
isa = PBXGroup;
children = (
4B7FBFF924EC936C002D12A1 /* EnvVarTest */,
4B7FBFE424EC92F2002D12A1 /* Products */,
);
sourceTree = "<group>";
};
4B7FBFE424EC92F2002D12A1 /* Products */ = {
isa = PBXGroup;
children = (
4B7FBFF824EC936C002D12A1 /* EnvVarTest.app */,
);
name = Products;
sourceTree = "<group>";
};
4B7FBFF924EC936C002D12A1 /* EnvVarTest */ = {
isa = PBXGroup;
children = (
4B7FBFFA24EC936C002D12A1 /* AppDelegate.swift */,
4B7FBFFC24EC936E002D12A1 /* Assets.xcassets */,
4B7FBFFE24EC936E002D12A1 /* MainMenu.xib */,
4B7FC00124EC936E002D12A1 /* Info.plist */,
);
path = EnvVarTest;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
4B7FBFF724EC936C002D12A1 /* EnvVarTest */ = {
isa = PBXNativeTarget;
buildConfigurationList = 4B7FC00324EC936E002D12A1 /* Build configuration list for PBXNativeTarget "EnvVarTest" */;
buildPhases = (
4B7FBFF424EC936C002D12A1 /* Sources */,
4B7FBFF524EC936C002D12A1 /* Frameworks */,
4B7FBFF624EC936C002D12A1 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = EnvVarTest;
packageProductDependencies = (
4B7FC00724EC9425002D12A1 /* Commons */,
);
productName = EnvVarTest;
productReference = 4B7FBFF824EC936C002D12A1 /* EnvVarTest.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
4B7FBFDB24EC92F2002D12A1 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 1200;
LastUpgradeCheck = 1620;
TargetAttributes = {
4B7FBFF724EC936C002D12A1 = {
CreatedOnToolsVersion = 12.0;
};
};
};
buildConfigurationList = 4B7FBFDE24EC92F2002D12A1 /* Build configuration list for PBXProject "CommonsSupport" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 4B7FBFDA24EC92F2002D12A1;
productRefGroup = 4B7FBFE424EC92F2002D12A1 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
4B7FBFF724EC936C002D12A1 /* EnvVarTest */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
4B7FBFF624EC936C002D12A1 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4B7FBFFD24EC936E002D12A1 /* Assets.xcassets in Resources */,
4B7FC00024EC936E002D12A1 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
4B7FBFF424EC936C002D12A1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4B7FBFFB24EC936C002D12A1 /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
4B7FBFFE24EC936E002D12A1 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
4B7FBFFF24EC936E002D12A1 /* Base */,
);
name = MainMenu.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
4B7FBFEF24EC92F3002D12A1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 14.6;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 6.0;
};
name = Debug;
};
4B7FBFF024EC92F3002D12A1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 14.6;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 6.0;
};
name = Release;
};
4B7FC00424EC936E002D12A1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
INFOPLIST_FILE = EnvVarTest/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.EnvVarTest;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
4B7FC00524EC936E002D12A1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
INFOPLIST_FILE = EnvVarTest/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.EnvVarTest;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
4B7FBFDE24EC92F2002D12A1 /* Build configuration list for PBXProject "CommonsSupport" */ = {
isa = XCConfigurationList;
buildConfigurations = (
4B7FBFEF24EC92F3002D12A1 /* Debug */,
4B7FBFF024EC92F3002D12A1 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
4B7FC00324EC936E002D12A1 /* Build configuration list for PBXNativeTarget "EnvVarTest" */ = {
isa = XCConfigurationList;
buildConfigurations = (
4B7FC00424EC936E002D12A1 /* Debug */,
4B7FC00524EC936E002D12A1 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */
4B7FC00724EC9425002D12A1 /* Commons */ = {
isa = XCSwiftPackageProductDependency;
productName = Commons;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 4B7FBFDB24EC92F2002D12A1 /* Project object */;
}
================================================
FILE: Commons/Support/EnvVarTest/AppDelegate.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
import Commons
@main
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet var window: NSWindow!
@IBOutlet var textView: NSTextView!
func applicationDidFinishLaunching(_: Notification) {
let selfEnv = ProcessInfo.processInfo.environment
let shellUrl = URL(fileURLWithPath: selfEnv["SHELL"] ?? "/bin/bash")
let env = ProcessUtils.envVars(of: shellUrl, usingInteractiveMode: false)
for (k, v) in env {
let str = NSAttributedString(string: "\(k): \(v)\n")
print(str)
self.textView.textStorage?.append(str)
}
}
}
================================================
FILE: Commons/Support/EnvVarTest/Assets.xcassets/AccentColor.colorset/Contents.json
================================================
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: Commons/Support/EnvVarTest/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: Commons/Support/EnvVarTest/Assets.xcassets/Contents.json
================================================
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: Commons/Support/EnvVarTest/Base.lproj/MainMenu.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17147" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17147"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="EnvVarTest" customModuleProvider="target">
<connections>
<outlet property="textView" destination="Pa8-WR-2pk" id="mpC-ja-sK7"/>
<outlet property="window" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="EnvVarTest" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="EnvVarTest" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About EnvTest" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide EnvTest" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit EnvTest" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="File" id="dMs-cI-mzQ">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="File" id="bib-Uj-vzu">
<items>
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
<connections>
<action selector="newDocument:" target="-1" id="4Si-XN-c54"/>
</connections>
</menuItem>
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
<connections>
<action selector="openDocument:" target="-1" id="bVn-NM-KNZ"/>
</connections>
</menuItem>
<menuItem title="Open Recent" id="tXI-mr-wws">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
<items>
<menuItem title="Clear Menu" id="vNY-rz-j42">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="clearRecentDocuments:" target="-1" id="Daa-9d-B3U"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
<connections>
<action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/>
</connections>
</menuItem>
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
<connections>
<action selector="saveDocument:" target="-1" id="teZ-XB-qJY"/>
</connections>
</menuItem>
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
<connections>
<action selector="saveDocumentAs:" target="-1" id="mDf-zr-I0C"/>
</connections>
</menuItem>
<menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H">
<connections>
<action selector="revertDocumentToSaved:" target="-1" id="iJ3-Pv-kwq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="runPageLayout:" target="-1" id="Din-rz-gC5"/>
</connections>
</menuItem>
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
<connections>
<action selector="print:" target="-1" id="qaZ-4w-aoO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Format" id="jxT-CU-nIS">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Format" id="GEO-Iw-cKr">
<items>
<menuItem title="Font" id="Gi5-1S-RQB">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
<items>
<menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq">
<connections>
<action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/>
</connections>
</menuItem>
<menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27">
<connections>
<action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/>
</connections>
</menuItem>
<menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq">
<connections>
<action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/>
</connections>
</menuItem>
<menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
<connections>
<action selector="underline:" target="-1" id="FYS-2b-JAY"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL">
<connections>
<action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/>
</connections>
</menuItem>
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST">
<connections>
<action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
<menuItem title="Kern" id="jBQ-r6-VK2">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Kern" id="tlD-Oa-oAM">
<items>
<menuItem title="Use Default" id="GUa-eO-cwY">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardKerning:" target="-1" id="6dk-9l-Ckg"/>
</connections>
</menuItem>
<menuItem title="Use None" id="cDB-IK-hbR">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffKerning:" target="-1" id="U8a-gz-Maa"/>
</connections>
</menuItem>
<menuItem title="Tighten" id="46P-cB-AYj">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="tightenKerning:" target="-1" id="hr7-Nz-8ro"/>
</connections>
</menuItem>
<menuItem title="Loosen" id="ogc-rX-tC1">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="loosenKerning:" target="-1" id="8i4-f9-FKE"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Ligatures" id="o6e-r0-MWq">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
<items>
<menuItem title="Use Default" id="agt-UL-0e3">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardLigatures:" target="-1" id="7uR-wd-Dx6"/>
</connections>
</menuItem>
<menuItem title="Use None" id="J7y-lM-qPV">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffLigatures:" target="-1" id="iX2-gA-Ilz"/>
</connections>
</menuItem>
<menuItem title="Use All" id="xQD-1f-W4t">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useAllLigatures:" target="-1" id="KcB-kA-TuK"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Baseline" id="OaQ-X3-Vso">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Baseline" id="ijk-EB-dga">
<items>
<menuItem title="Use Default" id="3Om-Ey-2VK">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unscript:" target="-1" id="0vZ-95-Ywn"/>
</connections>
</menuItem>
<menuItem title="Superscript" id="Rqc-34-cIF">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="superscript:" target="-1" id="3qV-fo-wpU"/>
</connections>
</menuItem>
<menuItem title="Subscript" id="I0S-gh-46l">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="subscript:" target="-1" id="Q6W-4W-IGz"/>
</connections>
</menuItem>
<menuItem title="Raise" id="2h7-ER-AoG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="raiseBaseline:" target="-1" id="4sk-31-7Q9"/>
</connections>
</menuItem>
<menuItem title="Lower" id="1tx-W0-xDw">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowerBaseline:" target="-1" id="OF1-bc-KW4"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
<menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
<connections>
<action selector="orderFrontColorPanel:" target="-1" id="mSX-Xz-DV3"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
<menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="copyFont:" target="-1" id="GJO-xA-L4q"/>
</connections>
</menuItem>
<menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteFont:" target="-1" id="JfD-CL-leO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Text" id="Fal-I4-PZk">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Text" id="d9c-me-L2H">
<items>
<menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
<connections>
<action selector="alignLeft:" target="-1" id="zUv-R1-uAa"/>
</connections>
</menuItem>
<menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
<connections>
<action selector="alignCenter:" target="-1" id="spX-mk-kcS"/>
</connections>
</menuItem>
<menuItem title="Justify" id="J5U-5w-g23">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="alignJustified:" target="-1" id="ljL-7U-jND"/>
</connections>
</menuItem>
<menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
<connections>
<action selector="alignRight:" target="-1" id="r48-bG-YeY"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
<menuItem title="Writing Direction" id="H1b-Si-o9J">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
<items>
<menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="YGs-j5-SAR">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionNatural:" target="-1" id="qtV-5e-UBP"/>
</connections>
</menuItem>
<menuItem id="Lbh-J2-qVU">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionLeftToRight:" target="-1" id="S0X-9S-QSf"/>
</connections>
</menuItem>
<menuItem id="jFq-tB-4Kx">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionRightToLeft:" target="-1" id="5fk-qB-AqJ"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
<menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="Nop-cj-93Q">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionNatural:" target="-1" id="lPI-Se-ZHp"/>
</connections>
</menuItem>
<menuItem id="BgM-ve-c93">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionLeftToRight:" target="-1" id="caW-Bv-w94"/>
</connections>
</menuItem>
<menuItem id="RB4-Sm-HuC">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionRightToLeft:" target="-1" id="EXD-6r-ZUu"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
<menuItem title="Show Ruler" id="vLm-3I-IUL">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleRuler:" target="-1" id="FOx-HJ-KwY"/>
</connections>
</menuItem>
<menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="copyRuler:" target="-1" id="71i-fW-3W2"/>
</connections>
</menuItem>
<menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="pasteRuler:" target="-1" id="cSh-wd-qM2"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="toggleToolbarShown:" target="-1" id="BXY-wc-z0C"/>
</connections>
</menuItem>
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="runToolbarCustomizationPalette:" target="-1" id="pQI-g3-MTW"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
<menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleSidebar:" target="-1" id="iwa-gc-5KM"/>
</connections>
</menuItem>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="wpr-3q-Mcd">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items>
<menuItem title="EnvTest Help" keyEquivalent="?" id="FKE-Sm-Kum">
<connections>
<action selector="showHelp:" target="-1" id="y7X-2Q-9no"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
<point key="canvasLocation" x="139" y="154"/>
</menu>
<window title="EnvTest" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="335" y="390" width="480" height="360"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<view key="contentView" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<scrollView borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eua-Co-Zcr">
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="P9E-bd-O3r">
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textView editable="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" findStyle="bar" smartInsertDelete="YES" id="Pa8-WR-2pk">
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<size key="minSize" width="480" height="360"/>
<size key="maxSize" width="485" height="10000000"/>
<color key="insertionPointColor" name="textColor" catalog="System" colorSpace="catalog"/>
</textView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="Tdo-4y-1qW">
<rect key="frame" x="-100" y="-100" width="240" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="jul-RO-LsY">
<rect key="frame" x="464" y="0.0" width="16" height="360"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
</subviews>
<constraints>
<constraint firstItem="eua-Co-Zcr" firstAttribute="leading" secondItem="EiT-Mj-1SZ" secondAttribute="leading" id="BGk-yN-rSC"/>
<constraint firstAttribute="trailing" secondItem="eua-Co-Zcr" secondAttribute="trailing" id="QRE-vr-pLo"/>
<constraint firstAttribute="bottom" secondItem="eua-Co-Zcr" secondAttribute="bottom" id="Rx3-E7-eVE"/>
<constraint firstItem="eua-Co-Zcr" firstAttribute="top" secondItem="EiT-Mj-1SZ" secondAttribute="top" id="hf6-dd-Rhm"/>
</constraints>
</view>
<point key="canvasLocation" x="139" y="-120"/>
</window>
</objects>
</document>
================================================
FILE: Commons/Support/EnvVarTest/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
================================================
FILE: Commons/Tests/CommonsTests/ArrayCommonsTest.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Nimble
import XCTest
@testable import Commons
private class DummyToken: Comparable {
static func == (left: DummyToken, right: DummyToken) -> Bool {
left.value == right.value
}
static func < (left: DummyToken, right: DummyToken) -> Bool {
left.value < right.value
}
let value: String
init(_ value: String) {
self.value = value
}
}
class ArrayCommonsTest: XCTestCase {
func testTuplesToDict() {
let tuples = [
(1, "1"),
(2, "2"),
(3, "3"),
]
expect(tuplesToDict(tuples)).to(equal(
[
1: "1",
2: "2",
3: "3",
]
))
}
func testToDict() {
let array = [1, 2, 3]
expect(array.toDict { "\($0)" })
.to(equal(
[
1: "1",
2: "2",
3: "3",
]
))
}
func testSubstituting1() {
let substitute = [
DummyToken("a0"),
DummyToken("a1"),
DummyToken("a2"),
]
let array = [
DummyToken("b0"),
DummyToken("b1"),
DummyToken("a0"),
DummyToken("a1"),
DummyToken("b4"),
DummyToken("a2"),
]
let result = array.substituting(elements: substitute)
expect(result[2]).to(beIdenticalTo(substitute[0]))
expect(result[3]).to(beIdenticalTo(substitute[1]))
expect(result[5]).to(beIdenticalTo(substitute[2]))
expect(result).to(equal(array))
}
func testSubstituting2() {
let substitute = [
DummyToken("a0"),
DummyToken("a1"),
DummyToken("a2"),
]
let array = [
DummyToken("a0"),
DummyToken("b0"),
DummyToken("a1"),
DummyToken("b1"),
DummyToken("a2"),
DummyToken("b4"),
]
let result = array.substituting(elements: substitute)
expect(result[0]).to(beIdenticalTo(substitute[0]))
expect(result[2]).to(beIdenticalTo(substitute[1]))
expect(result[4]).to(beIdenticalTo(substitute[2]))
expect(result).to(equal(array))
}
func testSubstituting3() {
let substitute = [
DummyToken("a0"),
DummyToken("a1"),
DummyToken("a2"),
]
let array = [
DummyToken("b0"),
DummyToken("b1"),
DummyToken("b4"),
DummyToken("a0"),
DummyToken("a1"),
DummyToken("a2"),
]
let result = array.substituting(elements: substitute)
expect(result[3]).to(beIdenticalTo(substitute[0]))
expect(result[4]).to(beIdenticalTo(substitute[1]))
expect(result[5]).to(beIdenticalTo(substitute[2]))
expect(result).to(equal(array))
}
func testSubstituting4() {
let substitute = [
DummyToken("a0"),
DummyToken("a1"),
DummyToken("a2"),
]
let array = [
DummyToken("a0"),
DummyToken("a1"),
DummyToken("a2"),
DummyToken("b0"),
DummyToken("b1"),
DummyToken("b4"),
]
let result = array.substituting(elements: substitute)
expect(result[0]).to(beIdenticalTo(substitute[0]))
expect(result[1]).to(beIdenticalTo(substitute[1]))
expect(result[2]).to(beIdenticalTo(substitute[2]))
expect(result).to(equal(array))
}
func testSubstituting5() {
let substitute = [
DummyToken("a0"),
DummyToken("something else"),
DummyToken("a1"),
DummyToken("a2"),
]
let array = [
DummyToken("a0"),
DummyToken("b0"),
DummyToken("a1"),
DummyToken("b1"),
DummyToken("a2"),
DummyToken("b4"),
]
let result = array.substituting(elements: substitute)
expect(result[0]).to(beIdenticalTo(substitute[0]))
expect(result[2]).to(beIdenticalTo(substitute[2]))
expect(result[4]).to(beIdenticalTo(substitute[3]))
expect(result).to(equal(array))
}
}
================================================
FILE: Commons/Tests/CommonsTests/DictionaryCommonsTest.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Nimble
import XCTest
class DictionaryCommonsTest: XCTestCase {
func testMapToDict() {
let dict = [
1: "a",
2: "b",
3: "c",
]
expect(dict.mapToDict { k, v in (v, "\(k)-\(v)") }).to(equal(
[
"a": "1-a",
"b": "2-b",
"c": "3-c",
]
))
}
func testFlatMapToDict() {
let dict = [
1: "a",
2: "b",
3: "c",
]
expect(dict.flatMapToDict { k, v in
if k == 2 {
return nil
}
return (v, "\(k)-\(v)")
}).to(equal(
[
"a": "1-a",
"c": "3-c",
]
))
}
}
================================================
FILE: Commons/Tests/CommonsTests/FifoCacheTest.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Nimble
import XCTest
@testable import Commons
class FifoCacheTest: XCTestCase {
var fifo: FifoCache<Int, Int>!
override func setUp() {
super.setUp()
self.fifo = FifoCache(count: 10)
}
func testSimpleGet() {
for i in 0...5 {
self.fifo.set(i, forKey: i)
}
for i in 0...5 {
expect(self.fifo.valueForKey(i)).to(equal(i))
}
for i in 6..<10 {
expect(self.fifo.valueForKey(i)).to(beNil())
}
}
func testGet() {
for i in 0..<(10 * 3) {
self.fifo.set(i, forKey: i)
}
for i in 20..<30 {
expect(self.fifo.valueForKey(i)).to(equal(i))
}
expect(self.fifo.valueForKey(19)).to(beNil())
expect(self.fifo.valueForKey(30)).to(beNil())
}
}
================================================
FILE: Commons/Tests/CommonsTests/FileUtilsTest.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Nimble
import XCTest
@testable import Commons
class FileUtilsTest: XCTestCase {
var fileUtilsRsrcUrl = URL(fileURLWithPath: "/")
var a1Dir = URL(fileURLWithPath: "/")
override func setUp() {
self.fileUtilsRsrcUrl = Bundle.module.url(
forResource: "FileUtilsTest",
withExtension: "",
subdirectory: "Resources"
)!
self.a1Dir = self.fileUtilsRsrcUrl.appendingPathComponent("a1")
}
func testCommonParentOneDirUrl() {
let urls = [
fileUtilsRsrcUrl.appendingPathComponent("a1"),
]
expect(FileUtils.commonParent(of: urls)).to(equal(self.fileUtilsRsrcUrl))
}
func testCommonParentOneFileUrl() {
let urls = [
fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
]
expect(FileUtils.commonParent(of: urls)).to(equal(self.a1Dir))
}
func testCommonParentEmptyParams() {
expect(FileUtils.commonParent(of: []) as URL)
.to(equal(URL(fileURLWithPath: "/", isDirectory: true)))
}
func testCommonParent1() {
let urls = [
fileUtilsRsrcUrl.appendingPathComponent("a1"),
self.fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
]
expect(FileUtils.commonParent(of: urls)).to(equal(self.fileUtilsRsrcUrl))
}
func testCommonParent2() {
let urls = [
fileUtilsRsrcUrl.appendingPathComponent("a1"),
self.fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
self.fileUtilsRsrcUrl.appendingPathComponent("a1/a2/a1-a2-file1"),
]
expect(FileUtils.commonParent(of: urls)).to(equal(self.fileUtilsRsrcUrl))
}
func testBug1() {
let paths = [
fileUtilsRsrcUrl.appendingPathComponent("Downloads/test2/some/nginx.config"),
self.fileUtilsRsrcUrl.appendingPathComponent(".Trash/nginx.config"),
]
expect(FileUtils.commonParent(of: paths)).to(equal(self.fileUtilsRsrcUrl))
}
func testBug2() {
let paths = [
fileUtilsRsrcUrl.appendingPathComponent("Downloads/test2/some/nginx.config"),
self.fileUtilsRsrcUrl.appendingPathComponent(".Trash/nginx.config/de/nginx.config"),
]
expect(FileUtils.commonParent(of: paths)).to(equal(self.fileUtilsRsrcUrl))
}
func testCommonParent3() {
let urls = [
fileUtilsRsrcUrl.appendingPathComponent("a1"),
self.fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
self.fileUtilsRsrcUrl.appendingPathComponent("a1/a2/a1-a2-file1"),
self.fileUtilsRsrcUrl.appendingPathComponent("b1/b1-file1"),
]
expect(FileUtils.commonParent(of: urls)).to(equal(self.fileUtilsRsrcUrl))
}
func testCommonParent4() {
let urls = [
fileUtilsRsrcUrl.appendingPathComponent("a1"),
self.fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
self.fileUtilsRsrcUrl.appendingPathComponent("a1/a2/a1-a2-file1"),
self.fileUtilsRsrcUrl.appendingPathComponent("b1"),
]
expect(FileUtils.commonParent(of: urls)).to(equal(self.fileUtilsRsrcUrl))
}
func testCommonParent5() {
let urls = [
fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
self.fileUtilsRsrcUrl.appendingPathComponent("a1/a2/a1-a2-file1"),
self.fileUtilsRsrcUrl.appendingPathComponent("a1/a2"),
]
expect(FileUtils.commonParent(of: urls)).to(equal(self.a1Dir))
}
}
================================================
FILE: Commons/Tests/CommonsTests/Resources/FileUtilsTest/a1/a1-file1
================================================
================================================
FILE: Commons/Tests/CommonsTests/Resources/FileUtilsTest/a1/a2/a1-a2-file1
================================================
================================================
FILE: Commons/Tests/CommonsTests/Resources/FileUtilsTest/b1/b1-file1
================================================
================================================
FILE: Commons/Tests/CommonsTests/Resources/UrlCommonsTest/.dot-hidden-file
================================================
================================================
FILE: Commons/Tests/CommonsTests/Resources/UrlCommonsTest/dummy.rtfd/TXT.rtf
================================================
{\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
{\*\expandedcolortbl;;}
\paperw11900\paperh16840\margl1440\margr1440\vieww10800\viewh8400\viewkind0
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0
\f0\fs24 \cf0 Dummy RTFD}
================================================
FILE: Commons/Tests/CommonsTests/StringCommonsTest.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Nimble
import XCTest
class StringCommonsTest: XCTestCase {
func testWithoutPrefix() {
expect("prefixAbc".without(prefix: "prefix")).to(equal("Abc"))
expect("prefix".without(prefix: "prefix")).to(equal(""))
expect("Abcprefix".without(prefix: "prefix")).to(equal("Abcprefix"))
}
}
================================================
FILE: Commons/Tests/CommonsTests/SwiftCommonsTest.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
import Nimble
import XCTest
@testable import Commons
struct Dummy {
var value: Int
var marker: Bool
}
class ArraySliceTest: XCTestCase {
func testArraySliceGroup1() {
let grouped = [
Dummy(value: 0, marker: true),
Dummy(value: 0, marker: true),
Dummy(value: 1, marker: false),
Dummy(value: 2, marker: false),
Dummy(value: 3, marker: false),
][1...3].groupedRanges { element in element.marker }
expect(grouped).to(equal(
[
1...1,
2...3,
]
))
}
func testArraySliceGroup2() {
let grouped = [
Dummy(value: 0, marker: false),
Dummy(value: 1, marker: false),
Dummy(value: 2, marker: false),
Dummy(value: 3, marker: true),
Dummy(value: 3, marker: true),
][1...3].groupedRanges { element in element.marker }
expect(grouped).to(equal(
[
1...2,
3...3,
]
))
}
func testArraySliceGroup3() {
let grouped = [
Dummy(value: 0, marker: true),
Dummy(value: 1, marker: true),
Dummy(value: 2, marker: true),
Dummy(value: 3, marker: true),
][1...2].groupedRanges { element in element.marker }
expect(grouped).to(equal(
[
1...2,
]
))
}
func testArraySliceGroup4() {
let grouped = [
Dummy(value: 0, marker: true),
Dummy(value: 0, marker: true),
Dummy(value: 1, marker: true),
Dummy(value: 1, marker: false),
Dummy(value: 1, marker: true),
Dummy(value: 1, marker: true),
Dummy(value: 1, marker: true),
][1...5].groupedRanges { element in element.marker }
expect(grouped).to(equal(
[
1...2,
3...3,
4...5,
]
))
}
func testArraySliceGroup5() {
let grouped = [
Dummy(value: 0, marker: true),
Dummy(value: 0, marker: true),
Dummy(value: 1, marker: true),
Dummy(value: 1, marker: true),
Dummy(value: 1, marker: false),
Dummy(value: 1, marker: true),
Dummy(value: 1, marker: true),
][1...5].groupedRanges { element in element.marker }
expect(grouped).to(equal(
[
1...3,
4...4,
5...5,
]
))
}
func testArraySliceGroup6() {
let grouped = [
Dummy(value: 0, marker: true),
Dummy(value: 0, marker: true),
Dummy(value: 0, marker: true),
][1...1].groupedRanges { element in element.marker }
expect(grouped).to(equal(
[
1...1,
]
))
}
func testArraySliceGroup7() {
let grouped = [
Dummy(value: 0, marker: true),
Dummy(value: 0, marker: true),
Dummy(value: 0, marker: false),
Dummy(value: 0, marker: true),
][1...2].groupedRanges { element in element.marker }
expect(grouped).to(equal(
[
1...1,
2...2,
]
))
}
}
class SwiftCommonsTest: XCTestCase {
func testArrayGroup1() {
let grouped = [
Dummy(value: 0, marker: true),
Dummy(value: 1, marker: false),
Dummy(value: 2, marker: false),
Dummy(value: 3, marker: false),
].groupedRanges { element in element.marker }
expect(grouped).to(equal(
[
0...0,
1...3,
]
))
}
func testArrayGroup2() {
let grouped = [
Dummy(value: 0, marker: false),
Dummy(value: 1, marker: false),
Dummy(value: 2, marker: false),
Dummy(value: 3, marker: true),
].groupedRanges { element in element.marker }
expect(grouped).to(equal(
[
0...2,
3...3,
]
))
}
func testArrayGroup3() {
let grouped = [
Dummy(value: 0, marker: true),
Dummy(value: 1, marker: true),
].groupedRanges { element in element.marker }
expect(grouped).to(equal(
[
0...1,
]
))
}
func testArrayGroup4() {
let grouped = [
Dummy(value: 0, marker: true),
Dummy(value: 1, marker: true),
Dummy(value: 1, marker: false),
Dummy(value: 1, marker: true),
Dummy(value: 1, marker: true),
].groupedRanges { element in element.marker }
expect(grouped).to(equal(
[
0...1,
2...2,
3...4,
]
))
}
func testArrayGroup5() {
let grouped = [
Dummy(value: 0, marker: true),
Dummy(value: 1, marker: true),
Dummy(value: 1, marker: true),
Dummy(value: 1, marker: false),
Dummy(value: 1, marker: true),
].groupedRanges { element in element.marker }
expect(grouped).to(equal(
[
0...2,
3...3,
4...4,
]
))
}
func testArrayGroup6() {
let grouped = [
Dummy(value: 0, marker: true),
].groupedRanges { element in element.marker }
expect(grouped).to(equal(
[
0...0,
]
))
}
}
================================================
FILE: Commons/Tests/CommonsTests/UrlCommonsTest.swift
================================================
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Nimble
import XCTest
class UrlCommonsTest: XCTestCase {
func testIsDirectParent() {
let parent = URL(fileURLWithPath: "/some/path")
let child = URL(fileURLWithPath: "/some/path/text.txt")
let noChild1 = URL(fileURLWithPath: "/some/where/else/text.txt")
let noChild2 = URL(fileURLWithPath: "/some/text.txt")
expect(parent.isParent(of: child)).to(beTrue())
expect(parent.isParent(of: noChild1)).to(beFalse())
expect(parent.isParent(of: noChild2)).to(beFalse())
}
func testIsParent() {
let parent = URL(fileURLWithPath: "/some/path")
let child1 = URL(fileURLWithPath: "/some/path/text.txt")
let child2 = URL(fileURLWithPath: "/some/path/deep/text.txt")
let noChild1 = URL(fileURLWithPath: "/some/where/else/text.txt")
let noChild2 = URL(fileURLWithPath: "/some/text.txt")
expect(parent.isAncestor(of: child1)).to(beTrue())
expect(parent.isAncestor(of: child2)).to(beTrue())
expect(parent.isAncestor(of: noChild1)).to(beFalse())
expect(parent.isAncestor(of: noChild2)).to(beFalse())
}
func testIsContained() {
let parent = URL(fileURLWithPath: "/some/path")
let child1 = URL(fileURLWithPath: "/some/path/text.txt")
let child2 = URL(fileURLWithPath: "/some/path/deep/text.txt")
let noChild1 = URL(fileURLWithPath: "/some/where/else/text.txt")
let noChild2 = URL(fileURLWithPath: "/some/text.txt")
expect(child1.isContained(in: parent)).to(beTrue())
expect(child2.isContained(in: parent)).to(beTrue())
expect(noChild1.isContained(in: parent)).to(beFalse())
expect(noChild2.isContained(in: parent)).to(beFalse())
}
func testParent() {
expect(URL(fileURLWithPath: "/some/path/").parent).to(equal(URL(fileURLWithPath: "/some/")))
expect(URL(fileURLWithPath: "/some/path/text.txt").parent)
.to(equal(URL(fileURLWithPath: "/some/path/")))
expect(URL(fileURLWithPath: "/").parent).to(equal(URL(fileURLWithPath: "/")))
}
func testIsHidden() {
let resourceUrl = Bundle.module.url(
forResource: "UrlCommonsTest",
withExtension: "",
subdirectory: "Resources"
)!
let hidden = resourceUrl.appendingPathComponent(".dot-hidden-file")
expect(hidden.isHidden).to(beTrue())
expect(resourceUrl.isHidden).to(beFalse())
}
func testIsPackage() {
let resourceUrl = Bundle.module.url(
forResource: "UrlCommonsTest",
withExtension: "",
subdirectory: "Resources"
)!
let package = resourceUrl.appendingPathComponent("dummy.rtfd")
expect(package.isPackage).to(beTrue())
expect(resourceUrl.isPackage).to(beFalse())
}
}
================================================
FILE: DEVELOP.md
================================================
## How to develop
VimR includes a stock Neovim. From Neovim `v0.10.0`, we provide pre-built universal Neovim,
see for instance <https://github.com/qvacua/vimr/releases/tag/neovim-v0.10.0-20240527.232810>.
In most cases, you can use the pre-built Neovim.
Run the following
```bash
clean=true for_dev=false ./bin/build_nvimserver.sh
```
to download and place the files in the appropriate places.
Now, you can just *run* VimR target in Xcode.
If you want to build Neovim locally, you can use
```bash
clean=true for_dev=true ./bin/build_nvimserver.sh
```
Afterwards, you can run VimR target in Xcode.
(This is used when generating source since we need some generated header files.)
### How to enable the Debug menu in Release build
```bash
defaults write com.qvacua.VimR enable-debug-menu 1
```
## How to release
### Neovim
* Update Neovim and generate sources:
```bash
clean=true use_committed_nvim=true ./bin/generate_sources.sh
```
Use `use_committed=false` if you want to use modified local Neovim submodule.
* Commit and push.
* Tag and push with the following
```bash
version=neovim-vX.Y.Z-$(date "+%Y%m%d.%H%M%S"); git tag -a "${version}" -m "${version}"; git push origin "${version}"
```
* Github action will build universal binary + runtime and package it.
* Update the version of Neovim in `/bin/neovim/resources/buildInfo.json`
### VimR
* Set a new version of VimR via
```bash
is_snapshot=true ./bin/set_new_versions.sh # for snapshot or
is_snapshot=false marketing_version=0.38.3 ./bin/set_new_versions.sh # for release
```
and commit. This will create a `${bundle_version}-snapshot/release.sh` file to be used
with `build_release.sh` and `release-notes.temp.md` for release notes.
* Tag with the name
- Snapshot: `snapshot/yyyymmdd.HHMMSS`
- Release: `vX.Y.Z-yyyymmdd.HHMMSS`
* Push
* Add release notes to `release-notes.temp.md`.
* Build the release via
```bash
release_spec_file=....sh \
./bin/build_release.sh
```
* Publish to GitHub and update appcast via
```bash
create_gh_release=true upload=true update_appcast=true \
release_spec_file=....sh \
./bin/publish_release.sh
```
* The `appcast{-snapshot}.xml` file is modified. Check and push.
================================================
FILE: Ignore/Package.swift
================================================
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "Ignore",
platforms: [.macOS(.v14)],
products: [
.library(name: "Ignore", targets: ["Ignore"]),
],
dependencies: [
.package(url: "https://github.com/qvacua/misc.swift", exact: "0.4.0"),
.package(url: "https://github.com/Quick/Nimble", from: "14.0.0"),
.package(url: "https://github.com/SimplyDanny/SwiftLintPlugins", from: "0.62.2"),
],
targets: [
.target(
name: "Ignore",
dependencies: [.product(name: "WildmatchC", package: "misc.swift")],
plugins: [.plugin(name: "SwiftLintBuildToolPlugin", package: "SwiftLintPlugins")]
),
.testTarget(
name: "IgnoreTests",
dependencies: ["Ignore", "Nimble"],
resources: [.copy("Resources")]
),
]
)
================================================
FILE: Ignore/README.md
================================================
# Ignore
A description of this package.
================================================
FILE: Ignore/Sources/Ignore/FileLineReader.swift
================================================
/// Tae Won Ha - http://taewon.de - @hataewon
/// See LICENSE
import Foundation
/// Reads the file at the given ``URL`` line by line.
/// The Unix line ending `LF` is used to determine lines.
/// Thus, it supports `LF` and `CRLF` files. It does not support the legacy Mac line ending `CR`.
public final class FileLineReader: Sequence {
public static let defaultLineBufferCount = 1024
public let url: URL
public var lineBufferCount: Int
public var encoding: String.Encoding
/// - Parameters:
/// - url: URL of the file.
/// - encoding: Encoding of the file. It's mutable.
/// After mutating, the next iterator will use the new value.
/// - lineBufferCount: The initial size of the buffer for reading lines. It's mutable.
/// After mutating, the next iterator will use the new value.
/// The default is ``FileLineReader/defaultLineBufferCount``.
public init(url: URL, encoding: String.Encoding, lineBufferCount: Int = defaultLineBufferCount) {
self.lineBufferCount = lineBufferCount
self.url = url
self.encoding = encoding
}
public func makeIterator() -> AnyIterator<String> {
guard let file = fopen(url.path, "r") else { return AnyIterator { nil } }
let iterator = LfLineIterator(
file: file,
encoding: self.encoding,
lineBufferCount: self.lineBufferCount
)
return AnyIterator { iterator.next() }
}
}
private class LfLineIterator: IteratorProtocol {
init(
file: UnsafeMutablePointer<FILE>,
encoding: String.Encoding,
lineBufferCount: Int
) {
self.file = file
self.encoding = encoding
self.buffer = Array(repeating: 0, count: lineBufferCount)
}
deinit { fclose(self.file) }
func next() -> String? {
var readCharCount = 0
while true {
let nextChar = getc(self.file)
if nextChar == EOF {
if readCharCount == 0 { return nil }
return String(
data: Data(
bytesNoCopy: self.buffer[0..<readCharCount].unsafeMutableRawPointer,
count: readCharCount,
deallocator: .none
), encoding: self.encoding
)
}
if readCharCount >= self.buffer.count {
// Array.append()
// https://developer.apple.com/documentation/swift/array/3126937-append
// "Complexity: O(1) on average, over many calls to append(_:) on the same array."
self.buffer.append(UInt8(nextChar))
} else {
self.buffer[readCharCount] = UInt8(nextChar)
}
readCharCount += 1
if nextChar == Self.unixLineEnding {
return String(
data: Data(
bytesNoCopy: self.buffer[0..<readCharCount].unsafeMutableRawPointer,
count: readCharCount,
deallocator: .none
), encoding: self.encoding
)
}
}
}
private let encoding: String.Encoding
private var buffer: [UInt8]
private let file: UnsafeMutablePointer<FILE>
private static let unixLineEnding = "\n".utf8.first!
}
private extension ArraySlice {
@inline(__always)
var unsafeMutableRawPointer: UnsafeMutableRawPointer {
UnsafeMutableRawPointer(mutating: self.withUnsafeBytes { $0.baseAddress! })
}
}
================================================
FILE: Ignore/Sources/Ignore/Filter.swift
================================================
/// Tae Won Ha - http://taewon.de - @hataewon
/// See LICENSE
import Foundation
import WildmatchC
public struct Filter: CustomStringConvertible {
public let base: URL
public let pattern: String
public let isAllow: Bool
public let isOnlyForDirectories: Bool
public let isRelativeToBase: Bool
public init(base: URL, pattern: String) {
self.base = base
var effectivePattern: String
self.isAllow = pattern.first == "!"
effectivePattern = self.isAllow ? String(pattern.dropFirst()) : pattern
self.isOnlyForDirectories = effectivePattern.last == "/"
effectivePattern =
self.isOnlyForDirectories ? String(effectivePattern.dropLast(1)) : effectivePattern
self.isRelativeToBase = effectivePattern.contains("/")
if self.isRelativeToBase {
effectivePattern = base.path
+ (effectivePattern.first == "/" ? effectivePattern : "/" + effectivePattern)
}
self.pattern = effectivePattern
self.patternCstr = Array(self.pattern.utf8CString)
}
public func disallows(_ url: URL) -> Bool {
if self.isOnlyForDirectories {
guard url.hasDirectoryPath else { return false }
}
if self.isRelativeToBase {
let matches = self.matches(url.path)
if self.isAllow { return !matches } else { return matches }
}
let matches = self.matches(url.lastPathComponent)
if self.isAllow { return false } else { return matches }
}
public func explicitlyAllows(_ url: URL) -> Bool {
if self.isOnlyForDirectories {
guard url.hasDirectoryPath else { return false }
}
if self.isRelativeToBase {
if self.isAllow { return self.matches(url.path) }
return false
}
if self.isAllow { return self.matches(url.lastPathComponent) } else { return false }
}
/// Ignores whether the pattern is only applicable for directories.
public func disallows(_ string: String) -> Bool {
if self.isAllow { false } else { self.matches(string) }
}
/// Ignores whether the pattern is only applicable for directories.
public func explicitlyAllows(_ string: String) -> Bool {
if self.isAllow { return self.matches(string) }
return false
}
public func matches(_ url: URL) -> Bool {
if self.isOnlyForDirectories {
guard url.hasDirectoryPath else { return false }
}
if self.isRelativeToBase {
return url.path.withCString { stringCstr in
wildmatch(self.patternCstr, stringCstr, WM_WILDSTAR) == WM_MATCH
}
}
return url.lastPathComponent.withCString { stringCstr in
wildmatch(self.patternCstr, stringCstr, WM_WILDSTAR) == WM_MATCH
}
}
/// Ignores whether the pattern is only applicable for directories.
public func matches(_ string: String) -> Bool {
string.withCString {
stringCstr in
wildmatch(self.patternCstr, stringCstr, WM_WILDSTAR) == WM_MATCH
}
}
public var description: String {
"Ignore(isAllow: \(self.isAllow), isOnlyDirectory: \(self.isOnlyForDirectories), "
+ "isAbsolute: \(self.isRelativeToBase), pattern: \(self.pattern), baseUrl: \(self.base))"
}
private let patternCstr: [CChar]
}
================================================
FILE: Ignore/Sources/Ignore/GitUtils.swift
================================================
/// Tae Won Ha - http://taewon.de - @hataewon
/// See LICENSE
import Foundation
public enum GitUtils {
static func globalGitignoreFileUrl() -> URL? {
guard let path = shellCommandOutput(
"git config --get core.excludesFile",
workingDirectory: fm.homeDirectoryForCurrentUser
),
FileManager.default.fileExists(atPath: path)
else { return nil }
return URL(fileURLWithPath: path)
}
static func gitDirInfoExcludeUrl(base: URL, gitRoot: URL? = nil) -> URL? {
guard let gitRoot = gitRoot == nil ? gitRootUrl(base: base) : gitRoot,
let gitDirName = shellCommandOutput("git rev-parse --git-dir", workingDirectory: gitRoot)
else { return nil }
let url = gitRoot.appendingPathComponent("\(gitDirName)/info/exclude")
guard fm.fileExists(atPath: url.path) else { return nil }
return url
}
static func gitRootUrl(base: URL) -> URL? {
guard let path = shellCommandOutput("git rev-parse --show-toplevel", workingDirectory: base)
else { return nil }
return URL(fileURLWithPath: path, isDirectory: true)
}
private static func shellCommandOutput(_ command: String, workingDirectory: URL) -> String? {
let task = Process()
let pipe = Pipe()
task.currentDirectoryURL = workingDirectory
task.standardInput = nil
task.standardOutput = pipe
task.standardError = nil
task.executableURL = URL(fileURLWithPath: "/bin/sh")
task.arguments = ["-c", command]
do {
try task.run()
task.waitUntilExit()
} catch {
return nil
}
guard task.terminationStatus == 0 else { return nil }
guard let output = String(
data: pipe.fileHandleForReading.readDataToEndOfFile(),
encoding: .utf8
) else { return nil }
let result = output.trimmingCharacters(in: .whitespacesAndNewlines)
if result.isEmpty { return nil } else { return result }
}
}
// FileManager is thread-safe:
// https://developer.apple.com/documentation/foundation/filemanager#1651181
private nonisolated(unsafe) let fm = FileManager.default
================================================
FILE: Ignore/Sources/Ignore/Ignore.swift
================================================
/// Tae Won Ha - http://taewon.de - @hataewon
/// See LICENSE
import Foundation
public final class Ignore {
public static let defaultIgnoreFileNames = [".ignore", ".gitignore"]
public static let vcsFolderPattern = [".svn/", ".hg/", ".git/"]
public static func globalGitignore(base: URL) -> Ignore? {
let gitRoot = GitUtils.gitRootUrl(base: base)
let urls = [
GitUtils.gitDirInfoExcludeUrl(base: base, gitRoot: gitRoot),
GitUtils.globalGitignoreFileUrl(),
].compactMap(\.self)
if urls.isEmpty { return nil }
if let gitRoot {
let vcsFolderFilters = self.vcsFolderPattern.map { Filter(base: gitRoot, pattern: $0) }
return Ignore(base: gitRoot, parent: nil, ignoreFileUrls: urls, prepend: vcsFolderFilters)
}
let vcsFolderFilters = self.vcsFolderPattern.map { Filter(base: base, pattern: $0) }
return Ignore(base: base, parent: nil, ignoreFileUrls: urls, prepend: vcsFolderFilters)
}
public static func parentOrIgnore(
for base: URL,
withParent parent: Ignore?,
ignoreFileNames: [String] = defaultIgnoreFileNames
) -> Ignore? {
let urls = ignoreFileNames
.map { base.appendingPathComponent($0) }
.filter { fm.fileExists(atPath: $0.path) }
.reversed()
if urls.isEmpty { return parent }
return Ignore(base: base, parent: parent, ignoreFileUrls: Array(urls))
}
public let filters: [Filter]
/// `ignoreFileUrls[n]` overrides `ignoreFileUrls[n + 1]`.
/// `Ignore`s of `parent` are overridden, if applicable, by the `Ignore`s found in `base`.
public init?(
base: URL,
parent: Ignore?,
ignoreFileUrls: [URL],
prepend: [Filter] = [],
append: [Filter] = []
) {
if ignoreFileUrls.isEmpty { return nil }
let urls = ignoreFileUrls.filter { fm.fileExists(atPath: $0.path) }.reversed()
self.filters = (parent?.filters ?? [])
+ prepend.reversed()
+ urls.flatMap {
FileLineReader(url: $0, encoding: .utf8)
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
.filter { !$0.isEmpty && !$0.starts(with: "#") }
.map { Filter(base: base, pattern: $0) }
}
+ append.reversed()
if self.filters.isEmpty { return nil }
if let lastAllowIndex = self.filters
.enumerated()
.filter({ _, ignore in ignore.isAllow })
.map(\.offset)
.max()
{
self.mixedIgnores = self.filters[0...lastAllowIndex]
self.remainingDisallowIgnores = self.filters[(lastAllowIndex + 1)...]
} else {
self.mixedIgnores = ArraySlice()
self.remainingDisallowIgnores = self.filters[0...]
}
}
/// `ignoreFileNames[n]` overrides `ignoreFileNames[n + 1]`.
/// `Ignore`s of `parent` are overridden, if applicable, by the `Ignore`s found in `base`.
public convenience init?(
base: URL,
parent: Ignore?,
ignoreFileNames: [String] = defaultIgnoreFileNames
) {
self.init(
base: base,
parent: parent,
ignoreFileUrls: ignoreFileNames.map { base.appendingPathComponent($0) }
)
}
public func excludes(_ url: URL) -> Bool {
var isExcluded = false
for ignore in self.mixedIgnores {
if ignore.isAllow {
if ignore.matches(url) { isExcluded = false }
} else {
if ignore.matches(url) { isExcluded = true }
}
}
if isExcluded { return true }
if self.remainingDisallowIgnores.contains(where: { $0.matches(url) }) {
return true
}
return false
}
let mixedIgnores: ArraySlice<Filter>
let remainingDisallowIgnores: ArraySlice<Filter>
}
// FileManager is thread-safe:
// https://developer.apple.com/documentation/foundation/filemanager#1651181
private nonisolated(unsafe) let fm = FileManager.default
================================================
FILE: Ignore/Tests/IgnoreTests/FileLineReaderTest.swift
================================================
/// Tae Won Ha - http://taewon.de - @hataewon
/// See LICENSE
import Nimble
import XCTest
@testable import Ignore
private struct TestSpec {
var fileName: String
var result: [String]
}
private let specs = [
TestSpec(fileName: "empty", result: []),
TestSpec(fileName: "unix-only-new-lines", result: ["\n", "\n", "\n"]),
TestSpec(fileName: "unix-no-line-ending-at-the-end", result: ["0123\n", "하태원\n", "abcde"]),
TestSpec(fileName: "unix-with-line-ending-at-the-end", result: ["0123\n", "하태원\n", "abcde\n"]),
TestSpec(fileName: "dos-only-new-lines", result: ["\r\n", "\r\n", "\r\n"]),
TestSpec(fileName: "dos-no-line-ending-at-the-end", result: ["0123\r\n", "하태원\r\n", "abcde"]),
TestSpec(
fileName: "dos-with-line-ending-at-the-end",
result: ["0123\r\n", "하태원\r\n", "abcde\r\n"]
),
]
final class FileLineReaderTest: XCTestCase {
func testSpecsDefaultBuffer() {
for spec in specs {
let url = Bundle.module.url(
forResource: spec.fileName,
withExtension: "txt",
subdirectory: "Resources/FileLineReaderTest"
)!
let lineReader = FileLineReader(url: url, encoding: .utf8)
let lines = Array(lineReader)
expect(lines).to(equal(spec.result))
}
}
func testSpecsSmallBuffer() {
for spec in specs {
let url = Bundle.module.url(
forResource: spec.fileName,
withExtension: "txt",
subdirectory: "Resources/FileLineReaderTest"
)!
let lineReader = FileLineReader(url: url, encoding: .utf8, lineBufferCount: 5)
let lines = Array(lineReader)
expect(lines).to(equal(spec.result))
}
}
func testSpecsBigBuffer() {
for spec in specs {
let url = Bundle.module.url(
forResource: spec.fileName,
withExtension: "txt",
subdirectory: "Resources/FileLineReaderTest"
)!
let lineReader = FileLineReader(url: url, encoding: .utf8, lineBufferCount: 2048)
let lines = Array(lineReader)
expect(lines).to(equal(spec.result))
}
}
}
================================================
FILE: Ignore/Tests/IgnoreTests/FilterTest.swift
================================================
/// Tae Won Ha - http://taewon.de - @hataewon
/// See LICENSE
import Nimble
import XCTest
@testable import Ignore
final class FilterTest: XCTestCase {
let root = Bundle.module.url(forResource: "Resources", withExtension: nil)!
func testProperties() {
var ignore = Filter(base: root, pattern: "/a")
expect(ignore.isAllow).to(beFalse())
expect(ignore.isRelativeToBase).to(beTrue())
expect(ignore.isOnlyForDirectories).to(beFalse())
ignore = Filter(base: self.root, pattern: "a/b")
expect(ignore.isAllow).to(beFalse())
expect(ignore.isRelativeToBase).to(beTrue())
expect(ignore.isOnlyForDirectories).to(beFalse())
ignore = Filter(base: self.root, pattern: "a/b/")
expect(ignore.isAllow).to(beFalse())
expect(ignore.isRelativeToBase).to(beTrue())
expect(ignore.isOnlyForDirectories).to(beTrue())
ignore = Filter(base: self.root, pattern: "a/")
expect(ignore.isAllow).to(beFalse())
expect(ignore.isRelativeToBase).to(beFalse())
expect(ignore.isOnlyForDirectories).to(beTrue())
ignore = Filter(base: self.root, pattern: "!a/")
expect(ignore.isAllow).to(beTrue())
expect(ignore.isRelativeToBase).to(beFalse())
expect(ignore.isOnlyForDirectories).to(beTrue())
}
func testNonRelativeIgnores() {
var ignore = Filter(base: root, pattern: "ab\\ ")
expect(ignore.disallows("ab ")).to(beTrue())
expect(ignore.disallows("ab")).to(beFalse())
ignore = Filter(base: self.root, pattern: "!include")
expect(ignore.explicitlyAllows("include")).to(beTrue())
expect(ignore.disallows("include")).to(beFalse())
expect(ignore.explicitlyAllows("no-include")).to(beFalse())
expect(ignore.disallows("no-include")).to(beFalse())
ignore = Filter(base: self.root, pattern: "a")
expect(ignore.disallows("a")).to(beTrue())
ignore = Filter(base: self.root, pattern: "*.png")
expect(ignore.disallows("a.png")).to(beTrue())
expect(ignore.disallows("b.png")).to(beTrue())
}
func testNonRelativeIgnoresUrl() {
var ignore = Filter(base: root, pattern: "ab\\ ")
expect(ignore.disallows(self.root.appendingPathComponent("ab "))).to(beTrue())
expect(ignore.explicitlyAllows(self.root.appendingPathComponent("ab"))).to(beFalse())
expect(ignore.disallows(self.root.appendingPathComponent("foo/bar/ab "))).to(beTrue())
expect(ignore.explicitlyAllows(self.root.appendingPathComponent("foo/bar/ab")))
.to(beFalse())
ignore = Filter(base: self.root, pattern: "!include")
expect(ignore.explicitlyAllows(self.root.appendingPathComponent("include"))).to(beTrue())
expect(ignore.disallows(self.root.appendingPathComponent("no-include"))).to(beFalse())
expect(ignore.explicitlyAllows(self.root.appendingPathComponent("foo/bar/include")))
.to(beTrue())
expect(ignore.disallows(self.root.appendingPathComponent("foo/bar/no-include")))
.to(beFalse())
ignore = Filter(base: self.root, pattern: "a")
expect(ignore.disallows(self.root.appendingPathComponent("a"))).to(beTrue())
expect(ignore.explicitlyAllows(self.root.appendingPathComponent("b"))).to(beFalse())
expect(ignore.disallows(self.root.appendingPathComponent("foo/bar/a"))).to(beTrue())
expect(ignore.explicitlyAllows(self.root.appendingPathComponent("foo/bar/b")))
.to(beFalse())
ignore = Filter(base: self.root, pattern: "*.png")
expect(ignore.disallows(self.root.appendingPathComponent("a.png"))).to(beTrue())
expect(ignore.disallows(self.root.appendingPathComponent("b.png"))).to(beTrue())
expect(ignore.explicitlyAllows(self.root.appendingPathComponent("c.jpg"))).to(beFalse())
expect(ignore.disallows(self.root.appendingPathComponent("foo/bar/a.png"))).to(beTrue())
expect(ignore.disallows(self.root.appendingPathComponent("foo/bar/b.png"))).to(beTrue())
expect(ignore.explicitlyAllows(self.root.appendingPathComponent("foo/bar/c.jpg")))
.to(beFalse())
}
func testRelativeIgnores() {
var ignore = Filter(base: root, pattern: "**/foo")
expect(ignore.disallows(self.root.appendingPathComponent("foo").path)).to(beTrue())
expect(ignore.disallows(self.root.appendingPathComponent("a/b/foo").path)).to(beTrue())
expect(ignore.explicitlyAllows(self.root.appendingPathComponent("a").path)).to(beFalse())
ignore = Filter(base: self.root, pattern: "abc/**")
expect(ignore.disallows(self.root.appendingPathComponent("abc/foo").path)).to(beTrue())
expect(ignore.disallows(self.root.appendingPathComponent("abc/def/foo").path))
.to(beTrue())
expect(ignore.explicitlyAllows(self.root.appendingPathComponent("a/b/c").path))
.to(beFalse())
ignore = Filter(base: self.root, pattern: "a/**/b")
expect(ignore.disallows(self.root.appendingPathComponent("a/b").path)).to(beTrue())
expect(ignore.disallows(self.root.appendingPathComponent("a/x/b").path)).to(beTrue())
expect(ignore.disallows(self.root.appendingPathComponent("a/x/y/b").path)).to(beTrue())
expect(ignore.explicitlyAllows(self.root.appendingPathComponent("a/x/y/c").path))
.to(beFalse())
}
func testRelativeIgnoresUrl() {
var ignore = Filter(base: root, pattern: "**/foo")
expect(ignore.disallows(self.root.appendingPathComponent("foo"))).to(beTrue())
expect(ignore.disallows(self.root.appendingPathComponent("a/b/foo"))).to(beTrue())
expect(ignore.explicitlyAllows(self.root.appendingPathComponent("a"))).to(beFalse())
ignore = Filter(base: self.root, pattern: "abc/**")
expect(ignore.disallows(self.root.appendingPathComponent("abc/foo"))).to(beTrue())
expect(ignore.disallows(self.root.appendingPathComponent("abc/def/foo")))
.to(beTrue())
expect(ignore.explicitlyAllows(self.root.appendingPathComponent("a/b/c"))).to(beFalse())
ignore = Filter(base: self.root, pattern: "a/**/b")
expect(ignore.disallows(self.root.appendingPathComponent("a/b"))).to(beTrue())
expect(ignore.disallows(self.root.appendingPathComponent("a/x/b"))).to(beTrue())
expect(ignore.disallows(self.root.appendingPathComponent("a/x/y/b"))).to(beTrue())
expect(ignore.explicitlyAllows(self.root.appendingPathComponent("a/x/y/c"))).to(beFalse())
}
}
================================================
FILE: Ignore/Tests/IgnoreTests/IgnoreSplitTest.swift
================================================
/// Tae Won Ha - http://taewon.de - @hataewon
/// See LICENSE
import Nimble
import XCTest
@testable import Ignore
private struct IgnoreSplittingTestSpec {
var fileName: String
var mixed: [String]
var disallow: [String]
}
private let ignoreSplittingTestSpecs = [
IgnoreSplittingTestSpec(
fileName: "ignore-splitting-0",
mixed: [],
disallow: ["*.a", "*.b", "*.c", "*.d"]
),
IgnoreSplittingTestSpec(
fileName: "ignore-splitting-1",
mixed: ["*.a"],
disallow: ["*.b", "*.c", "*.d"]
),
IgnoreSplittingTestSpec(
fileName: "ignore-splitting-2",
mixed: ["*.a", "*.b"],
disallow: ["*.c", "*.d"]
),
IgnoreSplittingTestSpec(
fileName: "ignore-splitting-3",
mixed: ["*.a", "*.b", "*.c"],
disallow: ["*.d"]
),
IgnoreSplittingTestSpec(
fileName: "ignore-splitting-4",
mixed: ["*.a", "*.b", "*.c", "*.d"],
disallow: []
),
]
final class IgnoreSplitTest: XCTestCase {
func testIgnoreSplitting() {
for spec in ignoreSplittingTestSpecs {
let url = Bundle.module.url(
forResource: "IgnoreCollectionTest",
withExtension: nil,
subdirectory: "Resources"
)!
let ignoreFile = Ignore(base: url, parent: nil, ignoreFileNames: [spec.fileName])!
expect(ignoreFile.mixedIgnores.map(\.pattern)).to(equal(spec.mixed))
expect(ignoreFile.remainingDisallowIgnores.map(\.pattern)).to(equal(spec.disallow))
}
}
}
================================================
FILE: Ignore/Tests/IgnoreTests/IgnoreTest.swift
================================================
/// Tae Won Ha - http://taewon.de - @hataewon
/// See LICENSE
import Nimble
import XCTest
@testable import Ignore
final class IgnoreTest: XCTestCase {
func testIgnoreSplitting() {
let root = Bundle.module.url(
forResource: "IgnoreCollectionTest",
withExtension: nil,
subdirectory: "Resources"
)!
let c = Ignore(base: root, parent: nil)!
expect(c.excludes(self.url("out", base: root, isDir: true))).to(beTrue())
expect(c.excludes(self.url("out", base: root, isDir: false))).to(beFalse())
expect(c.excludes(self.url("logs", base: root, isDir: true))).to(beTrue())
expect(c.excludes(self.url("logs", base: root, isDir: false))).to(beFalse())
expect(c.excludes(self.url("a.png", base: root))).to(beTrue())
expect(c.excludes(self.url("include-me", base: root))).to(beFalse())
expect(c.excludes(self.url("a/b/include-me", base: root))).to(beFalse())
expect(c.excludes(self.url("ignore-me", base: root))).to(beTrue())
expect(c.excludes(self.url("a/b/ignore-me", base: root))).to(beTrue())
}
private func url(_ path: String, base: URL, isDir: Bool = false) -> URL {
URL(fileURLWithPath: path, isDirectory: isDir, relativeTo: base)
}
}
================================================
FILE: Ignore/Tests/IgnoreTests/Resources/FileLineReaderTest/dos-no-line-ending-at-the-end.txt
================================================
0123
하태원
abcde
================================================
FILE: Ignore/Tests/IgnoreTests/Resources/FileLineReaderTest/dos-only-new-lines.txt
================================================
================================================
FILE: Ignore/Tests/IgnoreTests/Resources/FileLineReaderTest/dos-with-line-ending-at-the-end.txt
================================================
0123
하태원
abcde
================================================
FILE: Ignore/Tests/IgnoreTests/Resources/FileLineReaderTest/empty.txt
================================================
================================================
FILE: Ignore/Tests/IgnoreTests/Resources/FileLineReaderTest/unix-no-line-ending-at-the-end.txt
================================================
0123
하태원
abcde
================================================
FILE: Ignore/Tests/IgnoreTests/Resources/FileLineReaderTest/unix-only-new-lines.txt
================================================
================================================
FILE: Ignore/Tests/IgnoreTests/Resources/FileLineReaderTest/unix-with-line-ending-at-the-end.txt
================================================
0123
하태원
abcde
================================================
FILE: Ignore/Tests/IgnoreTests/Resources/IgnoreCollectionTest/.gitignore
================================================
*.png
# will be included below
include-me
vendor/
**/ignore-me
================================================
FILE: Ignore/Tests/IgnoreTests/Resources/IgnoreCollectionTest/.ignore
================================================
# include include-me file
!include-me
/logs/
/out/
================================================
FILE: Ignore/Tests/IgnoreTests/Resources/IgnoreCollectionTest/ignore-splitting-0
================================================
*.a
*.b
*.c
*.d
================================================
FILE: Ignore/Tests/IgnoreTests/Resources/IgnoreCollectionTest/ignore-splitting-1
================================================
!*.a
*.b
*.c
*.d
================================================
FILE: Ignore/Tests/IgnoreTests/Resources/IgnoreCollectionTest/ignore-splitting-2
================================================
*.a
!*.b
*.c
*.d
================================================
FILE: Ignore/Tests/IgnoreTests/Resources/IgnoreCollectionTest/ignore-splitting-3
================================================
!*.a
*.b
!*.c
*.d
================================================
FILE: Ignore/Tests/IgnoreTests/Resources/IgnoreCollectionTest/ignore-splitting-4
================================================
*.a
*.b
*.c
!*.d
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2025 Tae Won Ha
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: NvimApi/.gitignore
================================================
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: NvimApi/LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2024 Tae Won Ha
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: NvimApi/Package.swift
================================================
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "NvimApi",
platforms: [.macOS(.v14)],
products: [
.library(name: "NvimApi", targets: ["NvimApi"]),
],
dependencies: [
.package(url: "https://github.com/qvacua/MessagePack.swift", .upToNextMinor(from: "4.1.0")),
.package(url: "https://github.com/Kitura/BlueSocket", .upToNextMinor(from: "2.0.2")),
.package(url: "https://github.com/SimplyDanny/SwiftLintPlugins", from: "0.62.2"),
.package(name: "Commons", path: "../Commons"),
],
targets: [
.target(
name: "NvimApi",
dependencies: [
.product(name: "MessagePack", package: "MessagePack.swift"),
.product(name: "Socket", package: "BlueSocket"),
"Commons",
],
plugins: [.plugin(name: "SwiftLintBuildToolPlugin", package: "SwiftLintPlugins")]
),
.testTarget(
name: "NvimApiTests",
dependencies: [
"NvimApi",
]
),
]
)
================================================
FILE: NvimApi/README.md
================================================
To generate the API Swift file, first checkout the correct ref, e.g.,
develop or update-neovim. Then,
```bash
./bin/generate_sources.sh
```
================================================
FILE: NvimApi/Sources/NvimApi/Defs.swift
================================================
/// Tae Won Ha - http://taewon.de - @hataewon
/// See LICENSE
import Commons
let dlog = DevLogger.shared
================================================
FILE: NvimApi/Sources/NvimApi/MsgpackRpc.swift
================================================
/// Tae Won Ha - http://taewon.de - @hataewon
/// See LICENSE
import Foundation
import MessagePack
import os
// Inspired by https://stackoverflow.com/a/76941591
extension Pipe {
private struct DataReader {
fileprivate let dataStream: AsyncStream<Data>
init(pipe: Pipe) {
let (stream, cont) = AsyncStream<Data>.makeStream()
self.dataStream = stream
cont.onTermination = { [weak pipe] _ in pipe?.fileHandleForReading.readabilityHandler = nil }
pipe.fileHandleForReading.readabilityHandler = { handle in
let data = handle.availableData
if data.isEmpty {
cont.finish()
return
} else {
cont.yield(data)
}
}
}
}
var asyncData: AsyncStream<Data> { DataReader(pipe: self).dataStream }
}
public actor MsgpackRpc {
public typealias Value = MessagePackValue
public enum MessageType: UInt64 {
case request = 0
case response = 1
case notification = 2
}
public enum Message: Sendable {
case response(msgid: UInt32, error: Value, result: Value)
case notification(method: String, params: [Value])
case error(value: Value, msg: String)
case request(msgid: UInt32, method: String, params: [Value])
}
public struct Response: Sendable {
public static func nilResponse(_ msgid: UInt32) -> Self {
.init(msgid: msgid, error: .nil, result: .nil)
}
public let msgid: UInt32
public let error: Value
public let result: Value
public var isSuccess: Bool { self.error.isNil }
public var isError: Bool { !self.isSuccess }
}
public struct Error: Swift.Error {
var msg: String
var cause: Swift.Error?
init(msg: String, cause: Swift.Error? = nil) {
self.msg = msg
self.cause = cause
}
}
public let messagesStream: AsyncStream<Message>
public init() {
(self.messagesStream, self.streamContinuation) = AsyncStream.makeStream()
}
public func run(inPipe: Pipe, outPipe: Pipe, errorPipe: Pipe) async throws {
self.inPipe = inPipe
self.outPipe = outPipe
self.errorPipe = errorPipe
try await self.startReading()
}
public func stop() {
dlog.debug("Stopping")
self.cleanUp()
}
public func response(msgid: UInt32, error: Value, result: Value) throws {
if self.closed {
dlog.debug("Not sending response because closed")
return
}
let packed = pack(
[
.uint(MessageType.response.rawValue),
.uint(UInt64(msgid)),
error,
result,
]
)
try self.inPipe?.fileHandleForWriting.write(contentsOf: packed)
}
public func request(
method: String,
params: [Value],
expectsReturnValue: Bool
) async throws -> Response {
if self.closed {
dlog.debug("Not sending request because closed")
return .nilResponse(0)
}
let msgid = self.nextMsgid
self.nextMsgid += 1
let packed = pack(
[
.uint(MessageType.request.rawValue),
.uint(UInt64(msgid)),
.string(method),
.array(params),
]
)
try self.inPipe?.fileHandleForWriting.write(contentsOf: packed)
if !expectsReturnValue {
return .nilResponse(msgid)
}
return await withCheckedContinuation { continuation in
self.pendingRequests[msgid] = continuation
}
}
// MARK: Private
private let logger = Logger(subsystem: "com.qvacua.NvimApi", category: "rpc")
private var closed = false
private let streamContinuation: AsyncStream<Message>.Continuation
private var inPipe: Pipe?
private var outPipe: Pipe?
private var errorPipe: Pipe?
private var readingTask: Task<Void, any Swift.Error>?
private var nextMsgid: UInt32 = 1
private var pendingRequests = [UInt32: CheckedContinuation<Response, Never>]()
private func startReading() async throws {
self.readingTask = Task.detached(priority: .high) {
dlog.debug("Start reading")
guard let dataStream = await self.outPipe?.asyncData else {
throw Error(msg: "Could not get the async data stream")
}
var buffer = Data()
for await data in dataStream {
do {
buffer.append(data)
let (values, remainder) = try self.unpackAllWithRemainder(buffer)
if let remainder {
buffer = remainder
} else {
buffer.removeAll(keepingCapacity: true)
}
// Do we have to check closed here before processing the msgs?
for value in values {
await self.processMessage(value)
}
}
}
dlog.debug("End reading")
await self.cleanUp()
}
}
private func cleanUp() {
if self.closed {
dlog.debug("MsgpackRpc already closed")
return
}
dlog.debug("Cleaning up")
self.closed = true
self.readingTask?.cancel()
self.readingTask = nil
self.inPipe?.fileHandleForReading.readabilityHandler = nil
self.inPipe?.fileHandleForWriting.closeFile()
self.outPipe?.fileHandleForReading.closeFile()
self.errorPipe?.fileHandleForReading.closeFile()
self.inPipe = nil
self.outPipe = nil
self.errorPipe = nil
self.streamContinuation.finish()
for (msgid, continuation) in self.pendingRequests {
continuation.resume(returning: .nilResponse(msgid))
}
self.pendingRequests.removeAll()
dlog.debug("MsgpackRpc closed")
}
private func processMessage(_ unpacked: Value) {
guard let array = unpacked.arrayValue else {
self.streamContinuation.yield(with: .success(.error(
value: unpacked,
msg: "Could not get the array from the message"
)))
return
}
guard let rawType = array[0].uint64Value, let type = MessageType(rawValue: rawType) else {
self.streamContinuation.yield(with: .success(.error(
value: unpacked, msg: "Could not get the type of the message"
)))
return
}
switch type {
case .response:
guard array.count == 4 else {
self.streamContinuation.yield(with: .success(.error(
value: unpacked,
msg: "Got an array of length \(array.count) for a message type response"
)))
return
}
guard let msgid64 = array[1].uint64Value else {
self.streamContinuation.yield(with: .success(.error(
value: unpacked, msg: "Could not get the msgid"
)))
return
}
self.processResponse(msgid: UInt32(msgid64), error: array[2], result: array[3])
case .notification:
guard array.count == 3 else {
self.streamContinuation.yield(with: .success(.error(
value: unpacked,
msg: "Got an array of length \(array.count) for a message type notification"
)))
return
}
guard let method = array[1].stringValue, let params = array[2].arrayValue else {
self.streamContinuation.yield(with: .success(.error(
value: unpacked,
msg: "Could not get the method and params"
)))
return
}
self.streamContinuation.yield(with: .success(.notification(
method: method, params: params
)))
case .request:
guard let msgid = array[1].uint32Value, let method = array[2].stringValue,
let params = array[3].arrayValue
else { return }
self.streamContinuation.yield(with: .success(.request(
msgid: msgid, method: method, params: params
)))
return
}
}
private func processResponse(msgid: UInt32, error: Value, result: Value) {
guard let continuation = self.pendingRequests.removeValue(forKey: msgid) else { return }
continuation.resume(returning: Response(msgid: msgid, error: error, result: result))
}
private nonisolated func unpackAllWithRemainder(_ data: Data) throws
-> (values: [Value], remainder: Data?)
{
var values = [Value]()
var remainderData: Data?
var subdata = Subdata(data: data)
while !subdata.isEmpty {
let value: Value
do {
(value, subdata) = try unpack(subdata, compatibility: false)
values.append(consume value)
} catch MessagePackError.insufficientData {
remainderData = subdata.data
break
}
}
return (values, remainderData)
}
}
================================================
FILE: NvimApi/Sources/NvimApi/NvimApi.generated.swift
================================================
// Auto generated for nvim version 0.11.5.
// See bin/generate_api_methods.py
import Foundation
import MessagePack
extension NvimApi {
public enum Error: Swift.Error, Sendable {
public static let exceptionRawValue = UInt64(0)
public static let validationRawValue = UInt64(1)
case exception(message: String)
case validation(message: String)
case blocked
case conversion(type: Any.Type)
case other(cause: Swift.Error)
case other(description: String)
case unknown
init(_ value: NvimApi.Value?) {
let array = value?.arrayValue
guard array?.count == 2 else {
self = .unknown
return
}
guard let rawValue = array?[0].uint64Value, let message = array?[1].stringValue else {
self = .unknown
return
}
switch rawValue {
case Error.exceptionRawValue: self = .exception(message: message)
case Error.validationRawValue: self = .validation(message: message)
default: self = .unknown
}
}
}
}
public extension NvimApi {
func nvimGetAutocmds(
opts: [String: NvimApi.Value],
errWhenBlocked: Bool = true
) async -> Result<NvimApi.Value, NvimApi.Error> {
let params: [NvimApi.Value] = [
.map(opts.mapToDict({ (NvimApi.Value.string($0), $1) })),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> NvimApi.Value {
guard let result = (Optional(value)) else {
throw NvimApi.Error.conversion(type: NvimApi.Value.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_get_autocmds", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> NvimApi.Value in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimCreateAutocmd(
event: NvimApi.Value,
opts: [String: NvimApi.Value],
errWhenBlocked: Bool = true
) async -> Result<Int, NvimApi.Error> {
let params: [NvimApi.Value] = [
event,
.map(opts.mapToDict({ (NvimApi.Value.string($0), $1) })),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> Int {
guard let result = (value.intValue) else {
throw NvimApi.Error.conversion(type: Int.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_create_autocmd", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> Int in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimDelAutocmd(
id: Int,
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(id)),
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_del_autocmd", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimClearAutocmds(
opts: [String: NvimApi.Value],
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.map(opts.mapToDict({ (NvimApi.Value.string($0), $1) })),
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_clear_autocmds", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimCreateAugroup(
name: String,
opts: [String: NvimApi.Value],
errWhenBlocked: Bool = true
) async -> Result<Int, NvimApi.Error> {
let params: [NvimApi.Value] = [
.string(name),
.map(opts.mapToDict({ (NvimApi.Value.string($0), $1) })),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> Int {
guard let result = (value.intValue) else {
throw NvimApi.Error.conversion(type: Int.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_create_augroup", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> Int in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimDelAugroupById(
id: Int,
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(id)),
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_del_augroup_by_id", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimDelAugroupByName(
name: String,
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.string(name),
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_del_augroup_by_name", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimExecAutocmds(
event: NvimApi.Value,
opts: [String: NvimApi.Value],
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
event,
.map(opts.mapToDict({ (NvimApi.Value.string($0), $1) })),
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_exec_autocmds", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufLineCount(
buffer: NvimApi.Buffer,
errWhenBlocked: Bool = true
) async -> Result<Int, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> Int {
guard let result = (value.intValue) else {
throw NvimApi.Error.conversion(type: Int.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_line_count", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> Int in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufAttach(
buffer: NvimApi.Buffer,
send_buffer: Bool,
opts: [String: NvimApi.Value],
errWhenBlocked: Bool = true
) async -> Result<Bool, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.bool(send_buffer),
.map(opts.mapToDict({ (NvimApi.Value.string($0), $1) })),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> Bool {
guard let result = (value.boolValue) else {
throw NvimApi.Error.conversion(type: Bool.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_attach", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> Bool in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufDetach(
buffer: NvimApi.Buffer,
errWhenBlocked: Bool = true
) async -> Result<Bool, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> Bool {
guard let result = (value.boolValue) else {
throw NvimApi.Error.conversion(type: Bool.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_detach", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> Bool in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufGetLines(
buffer: NvimApi.Buffer,
start: Int,
end: Int,
strict_indexing: Bool,
errWhenBlocked: Bool = true
) async -> Result<[String], NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.int(Int64(start)),
.int(Int64(end)),
.bool(strict_indexing),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> [String] {
guard let result = (value.arrayValue?.compactMap({ v in v.stringValue })) else {
throw NvimApi.Error.conversion(type: [String].self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_get_lines", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> [String] in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufSetLines(
buffer: NvimApi.Buffer,
start: Int,
end: Int,
strict_indexing: Bool,
replacement: [String],
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.int(Int64(start)),
.int(Int64(end)),
.bool(strict_indexing),
.array(replacement.map { .string($0) }),
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_set_lines", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufSetText(
buffer: NvimApi.Buffer,
start_row: Int,
start_col: Int,
end_row: Int,
end_col: Int,
replacement: [String],
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.int(Int64(start_row)),
.int(Int64(start_col)),
.int(Int64(end_row)),
.int(Int64(end_col)),
.array(replacement.map { .string($0) }),
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_set_text", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufGetText(
buffer: NvimApi.Buffer,
start_row: Int,
start_col: Int,
end_row: Int,
end_col: Int,
opts: [String: NvimApi.Value],
errWhenBlocked: Bool = true
) async -> Result<[String], NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.int(Int64(start_row)),
.int(Int64(start_col)),
.int(Int64(end_row)),
.int(Int64(end_col)),
.map(opts.mapToDict({ (NvimApi.Value.string($0), $1) })),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> [String] {
guard let result = (value.arrayValue?.compactMap({ v in v.stringValue })) else {
throw NvimApi.Error.conversion(type: [String].self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_get_text", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> [String] in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufGetOffset(
buffer: NvimApi.Buffer,
index: Int,
errWhenBlocked: Bool = true
) async -> Result<Int, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.int(Int64(index)),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> Int {
guard let result = (value.intValue) else {
throw NvimApi.Error.conversion(type: Int.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_get_offset", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> Int in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufGetVar(
buffer: NvimApi.Buffer,
name: String,
errWhenBlocked: Bool = true
) async -> Result<NvimApi.Value, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.string(name),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> NvimApi.Value {
guard let result = (Optional(value)) else {
throw NvimApi.Error.conversion(type: NvimApi.Value.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_get_var", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> NvimApi.Value in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufGetChangedtick(
buffer: NvimApi.Buffer,
errWhenBlocked: Bool = true
) async -> Result<Int, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> Int {
guard let result = (value.intValue) else {
throw NvimApi.Error.conversion(type: Int.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_get_changedtick", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> Int in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufGetKeymap(
buffer: NvimApi.Buffer,
mode: String,
errWhenBlocked: Bool = true
) async -> Result<[[String: NvimApi.Value]], NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.string(mode),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> [[String: NvimApi.Value]] {
guard let result = (msgPackArrayDictToSwift(value.arrayValue)) else {
throw NvimApi.Error.conversion(type: [[String: NvimApi.Value]].self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_get_keymap", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> [[String: NvimApi.Value]] in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufSetKeymap(
buffer: NvimApi.Buffer,
mode: String,
lhs: String,
rhs: String,
opts: [String: NvimApi.Value],
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.string(mode),
.string(lhs),
.string(rhs),
.map(opts.mapToDict({ (NvimApi.Value.string($0), $1) })),
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_set_keymap", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufDelKeymap(
buffer: NvimApi.Buffer,
mode: String,
lhs: String,
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.string(mode),
.string(lhs),
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_del_keymap", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufSetVar(
buffer: NvimApi.Buffer,
name: String,
value: NvimApi.Value,
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.string(name),
value,
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_set_var", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufDelVar(
buffer: NvimApi.Buffer,
name: String,
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.string(name),
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_del_var", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufGetName(
buffer: NvimApi.Buffer,
errWhenBlocked: Bool = true
) async -> Result<String, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> String {
guard let result = (value.stringValue) else {
throw NvimApi.Error.conversion(type: String.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_get_name", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> String in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufSetName(
buffer: NvimApi.Buffer,
name: String,
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.string(name),
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_set_name", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufIsLoaded(
buffer: NvimApi.Buffer,
errWhenBlocked: Bool = true
) async -> Result<Bool, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> Bool {
guard let result = (value.boolValue) else {
throw NvimApi.Error.conversion(type: Bool.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_is_loaded", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> Bool in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufDelete(
buffer: NvimApi.Buffer,
opts: [String: NvimApi.Value],
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.map(opts.mapToDict({ (NvimApi.Value.string($0), $1) })),
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_delete", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufIsValid(
buffer: NvimApi.Buffer,
errWhenBlocked: Bool = true
) async -> Result<Bool, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> Bool {
guard let result = (value.boolValue) else {
throw NvimApi.Error.conversion(type: Bool.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_is_valid", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> Bool in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufDelMark(
buffer: NvimApi.Buffer,
name: String,
errWhenBlocked: Bool = true
) async -> Result<Bool, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.string(name),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> Bool {
guard let result = (value.boolValue) else {
throw NvimApi.Error.conversion(type: Bool.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_del_mark", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> Bool in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufSetMark(
buffer: NvimApi.Buffer,
name: String,
line: Int,
col: Int,
opts: [String: NvimApi.Value],
errWhenBlocked: Bool = true
) async -> Result<Bool, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.string(name),
.int(Int64(line)),
.int(Int64(col)),
.map(opts.mapToDict({ (NvimApi.Value.string($0), $1) })),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> Bool {
guard let result = (value.boolValue) else {
throw NvimApi.Error.conversion(type: Bool.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_set_mark", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> Bool in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufGetMark(
buffer: NvimApi.Buffer,
name: String,
errWhenBlocked: Bool = true
) async -> Result<[Int], NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.string(name),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> [Int] {
guard let result = (value.arrayValue?.compactMap({ v in v.intValue })) else {
throw NvimApi.Error.conversion(type: [Int].self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_get_mark", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> [Int] in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufCall(
buffer: NvimApi.Buffer,
fun: NvimApi.Value,
errWhenBlocked: Bool = true
) async -> Result<NvimApi.Value, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
fun,
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> NvimApi.Value {
guard let result = (Optional(value)) else {
throw NvimApi.Error.conversion(type: NvimApi.Value.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_buf_call", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> NvimApi.Value in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimParseCmd(
str: String,
opts: [String: NvimApi.Value],
errWhenBlocked: Bool = true
) async -> Result<[String: NvimApi.Value], NvimApi.Error> {
let params: [NvimApi.Value] = [
.string(str),
.map(opts.mapToDict({ (NvimApi.Value.string($0), $1) })),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> [String: NvimApi.Value] {
guard let result = (msgPackDictToSwift(value.dictionaryValue)) else {
throw NvimApi.Error.conversion(type: [String: NvimApi.Value].self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_parse_cmd", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> [String: NvimApi.Value] in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimCmd(
cmd: [String: NvimApi.Value],
opts: [String: NvimApi.Value],
errWhenBlocked: Bool = true
) async -> Result<String, NvimApi.Error> {
let params: [NvimApi.Value] = [
.map(cmd.mapToDict({ (NvimApi.Value.string($0), $1) })),
.map(opts.mapToDict({ (NvimApi.Value.string($0), $1) })),
]
func transform(_ value: NvimApi.Value) throws(NvimApi.Error) -> String {
guard let result = (value.stringValue) else {
throw NvimApi.Error.conversion(type: String.self)
}
return result
}
if errWhenBlocked, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_cmd", params: params)
switch reqResult {
case let .success(value):
return Result { () throws(NvimApi.Error) -> String in
try transform(value)
}
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimCreateUserCommand(
name: String,
command: NvimApi.Value,
opts: [String: NvimApi.Value],
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.string(name),
command,
.map(opts.mapToDict({ (NvimApi.Value.string($0), $1) })),
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_create_user_command", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimDelUserCommand(
name: String,
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.string(name),
]
if expectsReturnValue, let error = await self.blockedError() { return .failure(error) }
let reqResult = await self.sendRequest(method: "nvim_del_user_command", params: params)
switch reqResult {
case .success:
return .success(())
case let .failure(error):
return .failure(.other(cause: error))
}
}
func nvimBufCreateUserCommand(
buffer: NvimApi.Buffer,
name: String,
command: NvimApi.Value,
opts: [String: NvimApi.Value],
expectsReturnValue: Bool = false
) async -> Result<Void, NvimApi.Error> {
let params: [NvimApi.Value] = [
.int(Int64(buffer.handle)),
.string(name),
command,
.map(opts.mapToDict({ (NvimApi.Value.string($0), $1) })),
]
if expectsReturnValue
gitextract_y2whn9_4/
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ └── build-universal-neovim.yml
├── .gitignore
├── .gitmodules
├── .swiftformat
├── .swiftlint.yml
├── Brewfile
├── Commons/
│ ├── .gitignore
│ ├── Package.swift
│ ├── README.md
│ ├── Sources/
│ │ ├── Commons/
│ │ │ ├── AppKitCommons.swift
│ │ │ ├── ConditionVariable.swift
│ │ │ ├── CoreCommons.swift
│ │ │ ├── Defs.swift
│ │ │ ├── FifoCache.swift
│ │ │ ├── FileUtils.swift
│ │ │ ├── FoundationCommons.swift
│ │ │ ├── LoggerCommons.swift
│ │ │ ├── ProcessUtils.swift
│ │ │ └── SwiftCommons.swift
│ │ └── CommonsObjC/
│ │ ├── NetUtils.m
│ │ └── include/
│ │ └── NetUtils.h
│ ├── Support/
│ │ ├── CommonsSupport.xcodeproj/
│ │ │ └── project.pbxproj
│ │ └── EnvVarTest/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AccentColor.colorset/
│ │ │ │ └── Contents.json
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ └── MainMenu.xib
│ │ └── Info.plist
│ └── Tests/
│ └── CommonsTests/
│ ├── ArrayCommonsTest.swift
│ ├── DictionaryCommonsTest.swift
│ ├── FifoCacheTest.swift
│ ├── FileUtilsTest.swift
│ ├── Resources/
│ │ ├── FileUtilsTest/
│ │ │ ├── a1/
│ │ │ │ ├── a1-file1
│ │ │ │ └── a2/
│ │ │ │ └── a1-a2-file1
│ │ │ └── b1/
│ │ │ └── b1-file1
│ │ └── UrlCommonsTest/
│ │ ├── .dot-hidden-file
│ │ └── dummy.rtfd/
│ │ └── TXT.rtf
│ ├── StringCommonsTest.swift
│ ├── SwiftCommonsTest.swift
│ └── UrlCommonsTest.swift
├── DEVELOP.md
├── Ignore/
│ ├── Package.swift
│ ├── README.md
│ ├── Sources/
│ │ └── Ignore/
│ │ ├── FileLineReader.swift
│ │ ├── Filter.swift
│ │ ├── GitUtils.swift
│ │ └── Ignore.swift
│ └── Tests/
│ └── IgnoreTests/
│ ├── FileLineReaderTest.swift
│ ├── FilterTest.swift
│ ├── IgnoreSplitTest.swift
│ ├── IgnoreTest.swift
│ └── Resources/
│ ├── FileLineReaderTest/
│ │ ├── dos-no-line-ending-at-the-end.txt
│ │ ├── dos-only-new-lines.txt
│ │ ├── dos-with-line-ending-at-the-end.txt
│ │ ├── empty.txt
│ │ ├── unix-no-line-ending-at-the-end.txt
│ │ ├── unix-only-new-lines.txt
│ │ └── unix-with-line-ending-at-the-end.txt
│ └── IgnoreCollectionTest/
│ ├── .gitignore
│ ├── .ignore
│ ├── ignore-splitting-0
│ ├── ignore-splitting-1
│ ├── ignore-splitting-2
│ ├── ignore-splitting-3
│ └── ignore-splitting-4
├── LICENSE
├── NvimApi/
│ ├── .gitignore
│ ├── LICENSE
│ ├── Package.swift
│ ├── README.md
│ ├── Sources/
│ │ └── NvimApi/
│ │ ├── Defs.swift
│ │ ├── MsgpackRpc.swift
│ │ ├── NvimApi.generated.swift
│ │ ├── NvimApi.swift
│ │ ├── NvimApiSync.generated.swift
│ │ └── NvimApiSync.swift
│ ├── Tests/
│ │ └── NvimApiTests/
│ │ ├── DictionaryExtensionTests.swift
│ │ ├── MsgpackRpcNeovimExample.swift
│ │ ├── NvimApiExample.swift
│ │ └── NvimApiSyncTest.swift
│ └── bin/
│ ├── api_generator_common.py
│ ├── generate_async_api_methods.py
│ ├── generate_sources.sh
│ ├── generate_sync_api_methods.py
│ └── requirements.txt
├── NvimView/
│ ├── .gitignore
│ ├── Package.swift
│ ├── README.md
│ ├── Sources/
│ │ └── NvimView/
│ │ ├── AttributesRunDrawer.swift
│ │ ├── CellAttributes.swift
│ │ ├── CellAttributesCollection.swift
│ │ ├── ColorUtils.swift
│ │ ├── Defs.swift
│ │ ├── FontUtils.swift
│ │ ├── Geometry.swift
│ │ ├── KeyUtils.swift
│ │ ├── MessagePackCommons.swift
│ │ ├── ModeInfo.swift
│ │ ├── NvimAutoCommandEvent.generated.swift
│ │ ├── NvimCursorModeShape.generated.swift
│ │ ├── NvimProcess.swift
│ │ ├── NvimView+Api.swift
│ │ ├── NvimView+Debug.swift
│ │ ├── NvimView+Dragging.swift
│ │ ├── NvimView+Draw.swift
│ │ ├── NvimView+Geometry.swift
│ │ ├── NvimView+Key.swift
│ │ ├── NvimView+MenuItems.swift
│ │ ├── NvimView+Mouse.swift
│ │ ├── NvimView+Objects.swift
│ │ ├── NvimView+RemoteOptions.swift
│ │ ├── NvimView+Resize.swift
│ │ ├── NvimView+TouchBar.swift
│ │ ├── NvimView+Types.swift
│ │ ├── NvimView+UiBridge.swift
│ │ ├── NvimView.swift
│ │ ├── Resources/
│ │ │ └── com.qvacua.NvimView.vim
│ │ ├── Runs.swift
│ │ ├── Typesetter.swift
│ │ └── UGrid.swift
│ ├── Support/
│ │ ├── DrawerDev/
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets/
│ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── Base.lproj/
│ │ │ │ └── MainMenu.xib
│ │ │ ├── Info.plist
│ │ │ ├── MyView.swift
│ │ │ └── NvimView.swift
│ │ ├── DrawerPerf/
│ │ │ ├── 0.json
│ │ │ ├── 1.json
│ │ │ ├── 2.json
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets/
│ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── Base.lproj/
│ │ │ │ └── MainMenu.xib
│ │ │ ├── FontTrait.swift
│ │ │ ├── Info.plist
│ │ │ ├── NvimView.swift
│ │ │ └── PerfTester.swift
│ │ ├── MinimalNvimViewDemo/
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets/
│ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── Base.lproj/
│ │ │ │ ├── Document.xib
│ │ │ │ └── MainMenu.xib
│ │ │ ├── Document.swift
│ │ │ └── Info.plist
│ │ └── NvimViewSupport.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── MinimalNvimViewDemo.xcscheme
│ └── Tests/
│ └── NvimViewTests/
│ ├── CellAttributesCollectionTest.swift
│ ├── NimbleCommons.swift
│ ├── TypesetterTest.swift
│ └── UGridTest.swift
├── README.md
├── Tabs/
│ ├── .gitignore
│ ├── Package.swift
│ ├── README.md
│ ├── Sources/
│ │ └── Tabs/
│ │ ├── DraggingSingleRowStackView.swift
│ │ ├── HorizontalOnlyScrollView.swift
│ │ ├── Tab.swift
│ │ ├── TabBar.swift
│ │ └── Theme.swift
│ └── Support/
│ ├── TabsSupport/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AccentColor.colorset/
│ │ │ │ └── Contents.json
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ └── MainMenu.xib
│ │ └── Info.plist
│ └── TabsSupport.xcodeproj/
│ └── project.pbxproj
├── VimR/
│ ├── Dev.xcconfig
│ ├── Release.xcconfig
│ ├── VimR/
│ │ ├── AdvancedPrefReducer.swift
│ │ ├── AdvencedPref.swift
│ │ ├── AppDelegate.swift
│ │ ├── AppDelegateReducer.swift
│ │ ├── AppKitCommons.swift
│ │ ├── AppearancePref.swift
│ │ ├── AppearancePrefReducer.swift
│ │ ├── Application.swift
│ │ ├── Assets.xcassets/
│ │ │ └── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ ├── Credits.rtf
│ │ │ ├── FileBrowserMenu.xib
│ │ │ ├── MainMenu.xib
│ │ │ ├── MainWindow.xib
│ │ │ ├── OpenQuicklyWindow.xib
│ │ │ └── PrefWindow.xib
│ │ ├── Bridge.h
│ │ ├── BufferList.swift
│ │ ├── BufferListReducer.swift
│ │ ├── Context.swift
│ │ ├── CoreDataStack.swift
│ │ ├── CssUtils.swift
│ │ ├── DefaultShortcuts.swift
│ │ ├── Defs.swift
│ │ ├── FileBrowser.swift
│ │ ├── FileBrowserReducer.swift
│ │ ├── FileItem+CoreDataClass.h
│ │ ├── FileItem+CoreDataClass.m
│ │ ├── FileMonitor.swift
│ │ ├── FileOutlineView.swift
│ │ ├── FoundationCommons.swift
│ │ ├── FuzzySearch.xcdatamodel/
│ │ │ └── contents
│ │ ├── FuzzySearchService.swift
│ │ ├── GeneralPref.swift
│ │ ├── GeneralPrefReducer.swift
│ │ ├── HtmlPreviewMiddleware.swift
│ │ ├── HtmlPreviewTool.swift
│ │ ├── HtmlPreviewToolReducer.swift
│ │ ├── HttpServerMiddleware.swift
│ │ ├── IgnoreService.swift
│ │ ├── ImageAndTextTableCell.swift
│ │ ├── Info.plist
│ │ ├── KeysPref.swift
│ │ ├── KeysPrefReducer.swift
│ │ ├── MainWindow+Actions.swift
│ │ ├── MainWindow+CustomTitle.swift
│ │ ├── MainWindow+Delegates.swift
│ │ ├── MainWindow+Types.swift
│ │ ├── MainWindow.swift
│ │ ├── MainWindowReducer.swift
│ │ ├── MarkdownPreviewMiddleware.swift
│ │ ├── MarkdownPreviewReducer.swift
│ │ ├── MarkdownTool.swift
│ │ ├── MarkdownToolReducer.swift
│ │ ├── OpenQuicklyFileViewRow.swift
│ │ ├── OpenQuicklyReducer.swift
│ │ ├── OpenQuicklyWindow.swift
│ │ ├── PrefMiddleware.swift
│ │ ├── PrefPane.swift
│ │ ├── PrefUtils.swift
│ │ ├── PrefWindow.swift
│ │ ├── PrefWindowReducer.swift
│ │ ├── Redux.swift
│ │ ├── Resources.swift
│ │ ├── RpcAppearanceReducer.swift
│ │ ├── RpcEvents.swift
│ │ ├── ScoredUrl.h
│ │ ├── ScoredUrl.m
│ │ ├── ShortcutItem.swift
│ │ ├── ShortcutService.swift
│ │ ├── ShortcutsPref.swift
│ │ ├── ShortcutsTableSubviews.swift
│ │ ├── States.swift
│ │ ├── Theme.swift
│ │ ├── ThemedTableSubviews.swift
│ │ ├── Throttler.swift
│ │ ├── ToolsPref.swift
│ │ ├── ToolsPrefReducer.swift
│ │ ├── Types.swift
│ │ ├── UiRoot.swift
│ │ ├── UiRootReducer.swift
│ │ ├── com.qvacua.VimR.vim
│ │ ├── macvim-file-icons/
│ │ │ ├── MacVim-applescript.icns
│ │ │ ├── MacVim-as.icns
│ │ │ ├── MacVim-asp.icns
│ │ │ ├── MacVim-bash.icns
│ │ │ ├── MacVim-bib.icns
│ │ │ ├── MacVim-bsh.icns
│ │ │ ├── MacVim-c.icns
│ │ │ ├── MacVim-cfg.icns
│ │ │ ├── MacVim-cgi.icns
│ │ │ ├── MacVim-cpp.icns
│ │ │ ├── MacVim-cs.icns
│ │ │ ├── MacVim-csfg.icns
│ │ │ ├── MacVim-css.icns
│ │ │ ├── MacVim-csv.icns
│ │ │ ├── MacVim-dtd.icns
│ │ │ ├── MacVim-dylan.icns
│ │ │ ├── MacVim-erl.icns
│ │ │ ├── MacVim-f.icns
│ │ │ ├── MacVim-fscript.icns
│ │ │ ├── MacVim-generic.icns
│ │ │ ├── MacVim-gtd.icns
│ │ │ ├── MacVim-h.icns
│ │ │ ├── MacVim-hs.icns
│ │ │ ├── MacVim-html.icns
│ │ │ ├── MacVim-ics.icns
│ │ │ ├── MacVim-inc.icns
│ │ │ ├── MacVim-ini.icns
│ │ │ ├── MacVim-io.icns
│ │ │ ├── MacVim-java.icns
│ │ │ ├── MacVim-js.icns
│ │ │ ├── MacVim-jsp.icns
│ │ │ ├── MacVim-lisp.icns
│ │ │ ├── MacVim-log.icns
│ │ │ ├── MacVim-m.icns
│ │ │ ├── MacVim-markdown.icns
│ │ │ ├── MacVim-mm.icns
│ │ │ ├── MacVim-patch.icns
│ │ │ ├── MacVim-perl.icns
│ │ │ ├── MacVim-php.icns
│ │ │ ├── MacVim-plist.icns
│ │ │ ├── MacVim-properties.icns
│ │ │ ├── MacVim-ps.icns
│ │ │ ├── MacVim-py.icns
│ │ │ ├── MacVim-rb.icns
│ │ │ ├── MacVim-rst.icns
│ │ │ ├── MacVim-sch.icns
│ │ │ ├── MacVim-sql.icns
│ │ │ ├── MacVim-tcl.icns
│ │ │ ├── MacVim-tex.icns
│ │ │ ├── MacVim-tsv.icns
│ │ │ ├── MacVim-txt.icns
│ │ │ ├── MacVim-vb.icns
│ │ │ ├── MacVim-vba.icns
│ │ │ ├── MacVim-vcf.icns
│ │ │ ├── MacVim-vim.icns
│ │ │ ├── MacVim-wiki.icns
│ │ │ ├── MacVim-xml.icns
│ │ │ ├── MacVim-xsl.icns
│ │ │ └── MacVim-yaml.icns
│ │ ├── markdown/
│ │ │ ├── color-overrides.css
│ │ │ ├── github-markdown.css
│ │ │ └── template.html
│ │ ├── preview/
│ │ │ ├── base.css
│ │ │ ├── empty.html
│ │ │ ├── error.html
│ │ │ ├── save-first.html
│ │ │ └── select-first.html
│ │ └── vimr
│ ├── VimR.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── VimR.xcscheme
│ └── VimRTests/
│ ├── IgnoreServiceTest.swift
│ ├── Info.plist
│ └── Resources/
│ └── ignore-service-test/
│ ├── .gitignore
│ └── a/
│ ├── .gitignore
│ └── aa/
│ └── aaa/
│ └── .gitignore
├── VimR.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ ├── IDEWorkspaceChecks.plist
│ └── WorkspaceSettings.xcsettings
├── Workspace/
│ ├── .gitignore
│ ├── Package.swift
│ ├── README.md
│ └── Sources/
│ └── Workspace/
│ ├── InnterToolBar.swift
│ ├── ProxyWorkspaceBar.swift
│ ├── Workspace.swift
│ ├── WorkspaceBar.swift
│ ├── WorkspaceTool.swift
│ └── WorkspaceToolButton.swift
├── appcast.xml
├── appcast_snapshot.xml
├── bin/
│ ├── .python-version
│ ├── README.md
│ ├── build_jenkins.sh
│ ├── build_nightly_jenkins.sh
│ ├── build_nvimserver.sh
│ ├── build_release.sh
│ ├── build_vimr.sh
│ ├── generate_autocmds.py
│ ├── generate_cursor_shape.py
│ ├── generate_sources.sh
│ ├── neovim/
│ │ ├── bin/
│ │ │ ├── .gitignore
│ │ │ ├── build_neovim.sh
│ │ │ ├── build_neovim_for_dev.sh
│ │ │ └── build_universal_neovim.sh
│ │ └── resources/
│ │ ├── NvimServer.entitlements
│ │ └── buildInfo.json
│ ├── notarize_vimr.sh
│ ├── pre-commit.py
│ ├── publish_release.sh
│ ├── requirements.txt
│ ├── set_appcast.py
│ ├── set_new_versions.sh
│ ├── setup_markdown_css.sh
│ ├── shelly.py
│ └── sign_vimr.sh
├── ci/
│ ├── README.md
│ └── create_build_job.groovy
├── docs/
│ └── notes-on-cocoa-text-input.md
└── resources/
├── appcast_template.xml
├── autocmds.template.swift
├── cursor_shape.template.swift
└── release-notes.md
SYMBOL INDEX (19 symbols across 7 files) FILE: NvimApi/bin/api_generator_common.py function snake_to_camel (line 7) | def snake_to_camel(snake_str): function nvim_type_to_swift (line 12) | def nvim_type_to_swift(nvim_type): function msgpack_to_swift (line 54) | def msgpack_to_swift(msgpack_value_name, type): function swift_to_msgpack_value (line 95) | def swift_to_msgpack_value(name, type): function parse_args (line 126) | def parse_args(raw_params): function parse_params (line 138) | def parse_params(raw_params): function parse_version (line 147) | def parse_version(version): function parse_error_types (line 151) | def parse_error_types(error_types): function parse_error_cases (line 163) | def parse_error_cases(error_types): FILE: NvimApi/bin/generate_async_api_methods.py function parse_function (line 208) | def parse_function(f): FILE: NvimApi/bin/generate_sync_api_methods.py function parse_function (line 112) | def parse_function(f): FILE: bin/generate_autocmds.py function convert (line 14) | def convert(line: str) -> tuple[str, str]: function swift_autocmds (line 19) | def swift_autocmds(version: str, template_string: str) -> str: FILE: bin/generate_cursor_shape.py function are_shapes_same (line 36) | def are_shapes_same() -> bool: function swift_shapes (line 45) | def swift_shapes() -> str: FILE: bin/pre-commit.py function lint (line 18) | def lint(changed_files: List[str]) -> None: function format (line 24) | def format(changed_files: List[str]) -> None: FILE: bin/shelly.py function sh (line 6) | def sh(cmd: str | List[str], check: bool = True) -> int: function shout (line 17) | def shout(cmd: str | List[str], check: bool = True) -> str:
Condensed preview — 376 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (6,599K chars).
[
{
"path": ".github/FUNDING.yml",
"chars": 642,
"preview": "# These are supported funding model platforms\n\ngithub: [qvacua]\npatreon: # Replace with a single Patreon username\nopen_c"
},
{
"path": ".github/workflows/build-universal-neovim.yml",
"chars": 1771,
"preview": "name: 'Universal Neovim'\non:\n push:\n tags:\n # example: neovim-v0.10.0-20240601.102525\n - neovim-v[0-9]+.[0"
},
{
"path": ".gitignore",
"chars": 151,
"preview": ".DS_Store\n\n.idea/\n*.ipr\n*.iws\n*.iml\n\n*.pbxuser\nxcuserdata\nDerivedData\n*.xcuserstate\n\n.vscode/\n\n.swiftpm\nPackage.resolved"
},
{
"path": ".gitmodules",
"chars": 80,
"preview": "[submodule \"Neovim\"]\n\tpath = Neovim\n\turl = https://github.com/neovim/neovim.git\n"
},
{
"path": ".swiftformat",
"chars": 404,
"preview": "--swiftversion 6.0\n\n--exclude **/*.template.swift,.build,.swiftpm\n\n--indent 2\n--maxwidth 100\n\n--self insert\n--wrapargume"
},
{
"path": ".swiftlint.yml",
"chars": 2288,
"preview": "disabled_rules:\n - trailing_comma\n - identifier_name\n - function_parameter_count\n - file_length\n - no_unchecked_sen"
},
{
"path": "Brewfile",
"chars": 155,
"preview": "brew 'coreutils'\nbrew 'gnu-sed'\nbrew 'libtool'\nbrew 'automake'\nbrew 'cmake'\nbrew 'pkg-config'\nbrew 'gettext'\nbrew 'ninja"
},
{
"path": "Commons/.gitignore",
"chars": 53,
"preview": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\nxcuserdata/\n"
},
{
"path": "Commons/Package.swift",
"chars": 769,
"preview": "// swift-tools-version: 6.0\n\nimport PackageDescription\n\nlet package = Package(\n name: \"Commons\",\n platforms: [.macOS(."
},
{
"path": "Commons/README.md",
"chars": 42,
"preview": "# Commons\n\nA description of this package.\n"
},
{
"path": "Commons/Sources/Commons/AppKitCommons.swift",
"chars": 4310,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport AppKit\n\npublic extension NSAttributedString "
},
{
"path": "Commons/Sources/Commons/ConditionVariable.swift",
"chars": 776,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\n\npublic final class ConditionVari"
},
{
"path": "Commons/Sources/Commons/CoreCommons.swift",
"chars": 317,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\n\npublic extension CFRange {\n sta"
},
{
"path": "Commons/Sources/Commons/Defs.swift",
"chars": 247,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\n\nenum Defs {\n static let loggerS"
},
{
"path": "Commons/Sources/Commons/FifoCache.swift",
"chars": 2072,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\nimport os\n\npublic final class Thr"
},
{
"path": "Commons/Sources/Commons/FileUtils.swift",
"chars": 2784,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport AppKit\nimport Cocoa\nimport UniformTypeIdenti"
},
{
"path": "Commons/Sources/Commons/FoundationCommons.swift",
"chars": 2797,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\nimport os\n\npublic extension Array"
},
{
"path": "Commons/Sources/Commons/LoggerCommons.swift",
"chars": 7032,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\nimport os\n\npublic extension Logge"
},
{
"path": "Commons/Sources/Commons/ProcessUtils.swift",
"chars": 3114,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\nimport os\n\npublic enum ProcessUti"
},
{
"path": "Commons/Sources/Commons/SwiftCommons.swift",
"chars": 2886,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\n\npublic func identity<T>(_ input:"
},
{
"path": "Commons/Sources/CommonsObjC/NetUtils.m",
"chars": 1682,
"preview": "/**\n * Greg Omelaenko - http://omelaen.co\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\n#import \"NetU"
},
{
"path": "Commons/Sources/CommonsObjC/include/NetUtils.h",
"chars": 204,
"preview": "/**\n * Greg Omelaenko - http://omelaen.co\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\n#import <Foun"
},
{
"path": "Commons/Support/CommonsSupport.xcodeproj/project.pbxproj",
"chars": 12108,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "Commons/Support/EnvVarTest/AppDelegate.swift",
"chars": 649,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Commons\n\n@main\nclass AppDelegat"
},
{
"path": "Commons/Support/EnvVarTest/Assets.xcassets/AccentColor.colorset/Contents.json",
"chars": 123,
"preview": "{\n \"colors\" : [\n {\n \"idiom\" : \"universal\"\n }\n ],\n \"info\" : {\n \"author\" : \"xcode\",\n \"version\" : 1\n }"
},
{
"path": "Commons/Support/EnvVarTest/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 904,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"mac\",\n \"scale\" : \"1x\",\n \"size\" : \"16x16\"\n },\n {\n \"idiom\" : "
},
{
"path": "Commons/Support/EnvVarTest/Assets.xcassets/Contents.json",
"chars": 63,
"preview": "{\n \"info\" : {\n \"author\" : \"xcode\",\n \"version\" : 1\n }\n}\n"
},
{
"path": "Commons/Support/EnvVarTest/Base.lproj/MainMenu.xib",
"chars": 53946,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "Commons/Support/EnvVarTest/Info.plist",
"chars": 970,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Commons/Tests/CommonsTests/ArrayCommonsTest.swift",
"chars": 3752,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Nimble\nimport XCTest\n\n@testable import Commo"
},
{
"path": "Commons/Tests/CommonsTests/DictionaryCommonsTest.swift",
"chars": 680,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Nimble\nimport XCTest\n\nclass DictionaryCommon"
},
{
"path": "Commons/Tests/CommonsTests/FifoCacheTest.swift",
"chars": 802,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Nimble\nimport XCTest\n\n@testable import Commo"
},
{
"path": "Commons/Tests/CommonsTests/FileUtilsTest.swift",
"chars": 3326,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Nimble\nimport XCTest\n\n@testable import Commo"
},
{
"path": "Commons/Tests/CommonsTests/Resources/FileUtilsTest/a1/a1-file1",
"chars": 0,
"preview": ""
},
{
"path": "Commons/Tests/CommonsTests/Resources/FileUtilsTest/a1/a2/a1-a2-file1",
"chars": 0,
"preview": ""
},
{
"path": "Commons/Tests/CommonsTests/Resources/FileUtilsTest/b1/b1-file1",
"chars": 0,
"preview": ""
},
{
"path": "Commons/Tests/CommonsTests/Resources/UrlCommonsTest/.dot-hidden-file",
"chars": 0,
"preview": ""
},
{
"path": "Commons/Tests/CommonsTests/Resources/UrlCommonsTest/dummy.rtfd/TXT.rtf",
"chars": 379,
"preview": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1504\\cocoasubrtf820\n{\\fonttbl\\f0\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green25"
},
{
"path": "Commons/Tests/CommonsTests/StringCommonsTest.swift",
"chars": 372,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Nimble\nimport XCTest\n\nclass StringCommonsTes"
},
{
"path": "Commons/Tests/CommonsTests/SwiftCommonsTest.swift",
"chars": 4871,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Nimble\nimport XCTest\n\n@testable"
},
{
"path": "Commons/Tests/CommonsTests/UrlCommonsTest.swift",
"chars": 2690,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Nimble\nimport XCTest\n\nclass UrlCommonsTest: "
},
{
"path": "DEVELOP.md",
"chars": 2258,
"preview": "## How to develop\n\nVimR includes a stock Neovim. From Neovim `v0.10.0`, we provide pre-built universal Neovim,\nsee for i"
},
{
"path": "Ignore/Package.swift",
"chars": 805,
"preview": "// swift-tools-version: 6.0\n\nimport PackageDescription\n\nlet package = Package(\n name: \"Ignore\",\n platforms: [.macOS(.v"
},
{
"path": "Ignore/README.md",
"chars": 41,
"preview": "# Ignore\n\nA description of this package.\n"
},
{
"path": "Ignore/Sources/Ignore/FileLineReader.swift",
"chars": 3194,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Foundation\n\n/// Reads the file at the given ``URL`"
},
{
"path": "Ignore/Sources/Ignore/Filter.swift",
"chars": 3129,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Foundation\nimport WildmatchC\n\npublic struct Filter"
},
{
"path": "Ignore/Sources/Ignore/GitUtils.swift",
"chars": 2058,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Foundation\n\npublic enum GitUtils {\n static func g"
},
{
"path": "Ignore/Sources/Ignore/Ignore.swift",
"chars": 3747,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Foundation\n\npublic final class Ignore {\n public s"
},
{
"path": "Ignore/Tests/IgnoreTests/FileLineReaderTest.swift",
"chars": 2028,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Nimble\nimport XCTest\n@testable import Ignore\n\npriv"
},
{
"path": "Ignore/Tests/IgnoreTests/FilterTest.swift",
"chars": 6194,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Nimble\nimport XCTest\n@testable import Ignore\n\nfina"
},
{
"path": "Ignore/Tests/IgnoreTests/IgnoreSplitTest.swift",
"chars": 1432,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Nimble\nimport XCTest\n@testable import Ignore\n\npriv"
},
{
"path": "Ignore/Tests/IgnoreTests/IgnoreTest.swift",
"chars": 1212,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Nimble\nimport XCTest\n@testable import Ignore\n\nfina"
},
{
"path": "Ignore/Tests/IgnoreTests/Resources/FileLineReaderTest/dos-no-line-ending-at-the-end.txt",
"chars": 16,
"preview": "0123\r\n하태원\r\nabcde"
},
{
"path": "Ignore/Tests/IgnoreTests/Resources/FileLineReaderTest/dos-only-new-lines.txt",
"chars": 6,
"preview": "\r\n\r\n\r\n"
},
{
"path": "Ignore/Tests/IgnoreTests/Resources/FileLineReaderTest/dos-with-line-ending-at-the-end.txt",
"chars": 18,
"preview": "0123\r\n하태원\r\nabcde\r\n"
},
{
"path": "Ignore/Tests/IgnoreTests/Resources/FileLineReaderTest/empty.txt",
"chars": 0,
"preview": ""
},
{
"path": "Ignore/Tests/IgnoreTests/Resources/FileLineReaderTest/unix-no-line-ending-at-the-end.txt",
"chars": 14,
"preview": "0123\n하태원\nabcde"
},
{
"path": "Ignore/Tests/IgnoreTests/Resources/FileLineReaderTest/unix-only-new-lines.txt",
"chars": 3,
"preview": "\n\n\n"
},
{
"path": "Ignore/Tests/IgnoreTests/Resources/FileLineReaderTest/unix-with-line-ending-at-the-end.txt",
"chars": 15,
"preview": "0123\n하태원\nabcde\n"
},
{
"path": "Ignore/Tests/IgnoreTests/Resources/IgnoreCollectionTest/.gitignore",
"chars": 66,
"preview": "*.png\n\n# will be included below\ninclude-me\n\nvendor/\n**/ignore-me\n\n"
},
{
"path": "Ignore/Tests/IgnoreTests/Resources/IgnoreCollectionTest/.ignore",
"chars": 52,
"preview": "# include include-me file\n!include-me\n\n/logs/\n/out/\n"
},
{
"path": "Ignore/Tests/IgnoreTests/Resources/IgnoreCollectionTest/ignore-splitting-0",
"chars": 15,
"preview": "*.a\n*.b\n*.c\n*.d"
},
{
"path": "Ignore/Tests/IgnoreTests/Resources/IgnoreCollectionTest/ignore-splitting-1",
"chars": 16,
"preview": "!*.a\n*.b\n*.c\n*.d"
},
{
"path": "Ignore/Tests/IgnoreTests/Resources/IgnoreCollectionTest/ignore-splitting-2",
"chars": 16,
"preview": "*.a\n!*.b\n*.c\n*.d"
},
{
"path": "Ignore/Tests/IgnoreTests/Resources/IgnoreCollectionTest/ignore-splitting-3",
"chars": 17,
"preview": "!*.a\n*.b\n!*.c\n*.d"
},
{
"path": "Ignore/Tests/IgnoreTests/Resources/IgnoreCollectionTest/ignore-splitting-4",
"chars": 16,
"preview": "*.a\n*.b\n*.c\n!*.d"
},
{
"path": "LICENSE",
"chars": 1077,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2025 Tae Won Ha\n\nPermission is hereby granted, free of charge, to any person obtain"
},
{
"path": "NvimApi/.gitignore",
"chars": 159,
"preview": ".DS_Store\n/.build\n/Packages\nxcuserdata/\nDerivedData/\n.swiftpm/configuration/registries.json\n.swiftpm/xcode/package.xcwor"
},
{
"path": "NvimApi/LICENSE",
"chars": 1077,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2024 Tae Won Ha\n\nPermission is hereby granted, free of charge, to any person obtain"
},
{
"path": "NvimApi/Package.swift",
"chars": 973,
"preview": "// swift-tools-version: 6.0\n\nimport PackageDescription\n\nlet package = Package(\n name: \"NvimApi\",\n platforms: [.macOS(."
},
{
"path": "NvimApi/README.md",
"chars": 142,
"preview": "To generate the API Swift file, first checkout the correct ref, e.g.,\ndevelop or update-neovim. Then,\n\n```bash\n./bin/gen"
},
{
"path": "NvimApi/Sources/NvimApi/Defs.swift",
"chars": 107,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Commons\n\nlet dlog = DevLogger.shared\n"
},
{
"path": "NvimApi/Sources/NvimApi/MsgpackRpc.swift",
"chars": 8280,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Foundation\nimport MessagePack\nimport os\n\n// Inspir"
},
{
"path": "NvimApi/Sources/NvimApi/NvimApi.generated.swift",
"chars": 211374,
"preview": "// Auto generated for nvim version 0.11.5.\n// See bin/generate_api_methods.py\n\nimport Foundation\nimport MessagePack\n\next"
},
{
"path": "NvimApi/Sources/NvimApi/NvimApi.swift",
"chars": 3886,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Foundation\nimport MessagePack\n\npublic actor NvimAp"
},
{
"path": "NvimApi/Sources/NvimApi/NvimApiSync.generated.swift",
"chars": 191809,
"preview": "// Auto generated for nvim version 0.11.5.\n// See bin/generate_api_methods.py\n\nimport Foundation\nimport MessagePack\n\npub"
},
{
"path": "NvimApi/Sources/NvimApi/NvimApiSync.swift",
"chars": 2323,
"preview": "import Foundation\nimport MessagePack\nimport os\nimport Socket\n\n/// Only supports requests\npublic class NvimApiSync: @unch"
},
{
"path": "NvimApi/Tests/NvimApiTests/DictionaryExtensionTests.swift",
"chars": 1918,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Foundation\nimport Testing\n@testable import NvimApi"
},
{
"path": "NvimApi/Tests/NvimApiTests/MsgpackRpcNeovimExample.swift",
"chars": 3448,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Foundation\nimport NvimApi\nimport Testing\n\n/// No r"
},
{
"path": "NvimApi/Tests/NvimApiTests/NvimApiExample.swift",
"chars": 2876,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Foundation\nimport NvimApi\nimport Testing\n\n/// No r"
},
{
"path": "NvimApi/Tests/NvimApiTests/NvimApiSyncTest.swift",
"chars": 1070,
"preview": "/// Tae Won Ha - http://taewon.de - @hataewon\n/// See LICENSE\n\nimport Foundation\nimport NvimApi\nimport Testing\n\nclass Nv"
},
{
"path": "NvimApi/bin/api_generator_common.py",
"chars": 4506,
"preview": "#!/usr/bin/env python3\n\nimport re\nimport textwrap\n\n\ndef snake_to_camel(snake_str):\n components = snake_str.split(\"_\")"
},
{
"path": "NvimApi/bin/generate_async_api_methods.py",
"chars": 5946,
"preview": "#!/usr/bin/env python3\n\nimport io\nimport os\nimport subprocess\nfrom string import Template\n\nimport msgpack\n\nfrom api_gene"
},
{
"path": "NvimApi/bin/generate_sources.sh",
"chars": 640,
"preview": "#!/bin/bash\nset -Eeuo pipefail\n\nreadonly clean=${clean:?\"true or false\"}\nreadonly NVIM_PATH=\"../Neovim/build/bin/nvim\"\n\n"
},
{
"path": "NvimApi/bin/generate_sync_api_methods.py",
"chars": 3820,
"preview": "#!/usr/bin/env python3\n\nimport io\nimport os\nimport subprocess\nfrom string import Template\n\nimport msgpack\n\nfrom api_gene"
},
{
"path": "NvimApi/bin/requirements.txt",
"chars": 8,
"preview": "msgpack\n"
},
{
"path": "NvimView/.gitignore",
"chars": 127,
"preview": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\nxcuserdata/\n\nSources/NvimView/Resources/runtime\nSources/NvimView/Resources/Nvim"
},
{
"path": "NvimView/Package.swift",
"chars": 1242,
"preview": "// swift-tools-version: 6.0\n\nimport PackageDescription\n\nlet package = Package(\n name: \"NvimView\",\n platforms: [.macOS("
},
{
"path": "NvimView/README.md",
"chars": 43,
"preview": "# NvimView\n\nA description of this package.\n"
},
{
"path": "NvimView/Sources/NvimView/AttributesRunDrawer.swift",
"chars": 5923,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n\nfinal class AttributesRunDrawer {\n v"
},
{
"path": "NvimView/Sources/NvimView/CellAttributes.swift",
"chars": 2871,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Commons\nimport MessagePack\n\npub"
},
{
"path": "NvimView/Sources/NvimView/CellAttributesCollection.swift",
"chars": 1461,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\n\nfinal class CellAttributesCollec"
},
{
"path": "NvimView/Sources/NvimView/ColorUtils.swift",
"chars": 1236,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Commons\n\nfinal class ColorUtils"
},
{
"path": "NvimView/Sources/NvimView/Defs.swift",
"chars": 290,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Commons\nimport Foundation\n\nenum Defs {\n sta"
},
{
"path": "NvimView/Sources/NvimView/FontUtils.swift",
"chars": 4420,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Commons\n\nprivate struct SizedFo"
},
{
"path": "NvimView/Sources/NvimView/Geometry.swift",
"chars": 1616,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n\npublic struct Position: CustomStringC"
},
{
"path": "NvimView/Sources/NvimView/KeyUtils.swift",
"chars": 2656,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n\nenum KeyUtils {\n static func isContr"
},
{
"path": "NvimView/Sources/NvimView/MessagePackCommons.swift",
"chars": 554,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\nimport MessagePack\n\nextension Mes"
},
{
"path": "NvimView/Sources/NvimView/ModeInfo.swift",
"chars": 1374,
"preview": "/**\n * Johann Rudloff - @cypheon\n * See LICENSE\n */\n\nimport MessagePack\n\npublic enum CursorShape: Equatable {\n case blo"
},
{
"path": "NvimView/Sources/NvimView/NvimAutoCommandEvent.generated.swift",
"chars": 2690,
"preview": "// Auto generated for nvim v0.11.6\n// See bin/generate_autocmds.py\n\nenum NvimAutoCommandEvent: String {\n\n case bufadd\n "
},
{
"path": "NvimView/Sources/NvimView/NvimCursorModeShape.generated.swift",
"chars": 492,
"preview": "// Auto generated for nvim v0.11.6\n// See bin/generate_cursor_shape.py\n\npublic enum CursorModeShape: String {\n\n case no"
},
{
"path": "NvimView/Sources/NvimView/NvimProcess.swift",
"chars": 3560,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Commons\nimport Foundation\nimport MessagePack"
},
{
"path": "NvimView/Sources/NvimView/NvimView+Api.swift",
"chars": 10469,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport MessagePack\nimport NvimApi\nimpo"
},
{
"path": "NvimView/Sources/NvimView/NvimView+Debug.swift",
"chars": 1812,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n\npublic extension NvimView {\n @IBActi"
},
{
"path": "NvimView/Sources/NvimView/NvimView+Dragging.swift",
"chars": 876,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n\npublic extension NvimView {\n overrid"
},
{
"path": "NvimView/Sources/NvimView/NvimView+Draw.swift",
"chars": 7601,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport os\n\nextension NvimView {\n over"
},
{
"path": "NvimView/Sources/NvimView/NvimView+Geometry.swift",
"chars": 2342,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n\nextension NvimView {\n func cursorReg"
},
{
"path": "NvimView/Sources/NvimView/NvimView+Key.swift",
"chars": 11320,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport MessagePack\n\npublic extension N"
},
{
"path": "NvimView/Sources/NvimView/NvimView+MenuItems.swift",
"chars": 3544,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport NvimApi\n\n// MARK: - NSUserInter"
},
{
"path": "NvimView/Sources/NvimView/NvimView+Mouse.swift",
"chars": 7217,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport MessagePack\nimport NvimApi\n\npub"
},
{
"path": "NvimView/Sources/NvimView/NvimView+Objects.swift",
"chars": 1448,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\nimport NvimApi\n\npublic extension "
},
{
"path": "NvimView/Sources/NvimView/NvimView+RemoteOptions.swift",
"chars": 3404,
"preview": "/**\n * Renee Koecher - @shirk\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Mess"
},
{
"path": "NvimView/Sources/NvimView/NvimView+Resize.swift",
"chars": 1153,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport MessagePack\nimport NvimApi\n\next"
},
{
"path": "NvimView/Sources/NvimView/NvimView+TouchBar.swift",
"chars": 3863,
"preview": "/**\n * Greg Omelaenko - http://omelaen.co\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n"
},
{
"path": "NvimView/Sources/NvimView/NvimView+Types.swift",
"chars": 4860,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport MessagePack\nimport NvimApi\nimpo"
},
{
"path": "NvimView/Sources/NvimView/NvimView+UiBridge.swift",
"chars": 19683,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Carbon\nimport Cocoa\nimport Foundation\nimport"
},
{
"path": "NvimView/Sources/NvimView/NvimView.swift",
"chars": 15845,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Carbon\nimport Cocoa\nimport Commons\nimport Me"
},
{
"path": "NvimView/Sources/NvimView/Resources/com.qvacua.NvimView.vim",
"chars": 280,
"preview": "set mouse=a\nset title\n\nautocmd VimEnter,ColorScheme * :highlight default VimrDefaultCursor gui=reverse guibg=NONE guifg="
},
{
"path": "NvimView/Sources/NvimView/Runs.swift",
"chars": 286,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n\nstruct AttributesRun {\n var location"
},
{
"path": "NvimView/Sources/NvimView/Typesetter.swift",
"chars": 9619,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Commons\nimport os\n\nfinal class "
},
{
"path": "NvimView/Sources/NvimView/UGrid.swift",
"chars": 12135,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\nimport os\n\nstruct UUpdate: Codabl"
},
{
"path": "NvimView/Support/DrawerDev/AppDelegate.swift",
"chars": 404,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n\n@main\nclass AppDelegate: NSObject, NS"
},
{
"path": "NvimView/Support/DrawerDev/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 903,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"mac\",\n \"size\" : \"16x16\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : "
},
{
"path": "NvimView/Support/DrawerDev/Assets.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "NvimView/Support/DrawerDev/Base.lproj/MainMenu.xib",
"chars": 51746,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "NvimView/Support/DrawerDev/Info.plist",
"chars": 1060,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "NvimView/Support/DrawerDev/MyView.swift",
"chars": 5628,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n\n// let cells = [\"👨👨👧👧\", \"\", \"a\""
},
{
"path": "NvimView/Support/DrawerDev/NvimView.swift",
"chars": 450,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n\n// Dummy NvimView class for FontUtils"
},
{
"path": "NvimView/Support/DrawerPerf/0.json",
"chars": 1401958,
"preview": "{\n \"width\" : 153,\n \"cells\" : [\n [\n {\n \"string\" : \"2\",\n \"attrId\" : 74,\n \"flatCharIndex\" : "
},
{
"path": "NvimView/Support/DrawerPerf/1.json",
"chars": 1403601,
"preview": "{\n \"width\" : 153,\n \"cells\" : [\n [\n {\n \"string\" : \" \",\n \"attrId\" : 74,\n \"flatCharIndex\" : "
},
{
"path": "NvimView/Support/DrawerPerf/2.json",
"chars": 1355649,
"preview": "{\n \"width\" : 153,\n \"cells\" : [\n [\n {\n \"string\" : \" \",\n \"attrId\" : 54,\n \"flatCharIndex\" : "
},
{
"path": "NvimView/Support/DrawerPerf/AppDelegate.swift",
"chars": 1283,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport GameKit\nimport os\n\n@main\nclass "
},
{
"path": "NvimView/Support/DrawerPerf/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 870,
"preview": "{\n \"images\": [\n {\n \"idiom\": \"mac\",\n \"size\": \"16x16\",\n \"scale\": \"1x\"\n },\n {\n \"idiom\": \"mac\""
},
{
"path": "NvimView/Support/DrawerPerf/Assets.xcassets/Contents.json",
"chars": 60,
"preview": "{\n \"info\": {\n \"version\": 1,\n \"author\": \"xcode\"\n }\n}\n"
},
{
"path": "NvimView/Support/DrawerPerf/Base.lproj/MainMenu.xib",
"chars": 50751,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "NvimView/Support/DrawerPerf/FontTrait.swift",
"chars": 426,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\n\npublic struct FontTrait: OptionS"
},
{
"path": "NvimView/Support/DrawerPerf/Info.plist",
"chars": 1250,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "NvimView/Support/DrawerPerf/NvimView.swift",
"chars": 285,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n\n// Dummy NvimView class for FontUtils"
},
{
"path": "NvimView/Support/DrawerPerf/PerfTester.swift",
"chars": 4180,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n *\n * 0.json from: https://github.com/gshslatexintro/An-"
},
{
"path": "NvimView/Support/MinimalNvimViewDemo/AppDelegate.swift",
"chars": 921,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n\n// Hack\nextension Document: @unchecke"
},
{
"path": "NvimView/Support/MinimalNvimViewDemo/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 903,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"mac\",\n \"size\" : \"16x16\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : "
},
{
"path": "NvimView/Support/MinimalNvimViewDemo/Assets.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "NvimView/Support/MinimalNvimViewDemo/Base.lproj/Document.xib",
"chars": 2168,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "NvimView/Support/MinimalNvimViewDemo/Base.lproj/MainMenu.xib",
"chars": 51041,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "NvimView/Support/MinimalNvimViewDemo/Document.swift",
"chars": 2736,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport NvimView\nimport PureLayout\nimpo"
},
{
"path": "NvimView/Support/MinimalNvimViewDemo/Info.plist",
"chars": 1562,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "NvimView/Support/NvimViewSupport.xcodeproj/project.pbxproj",
"chars": 38280,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 60;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "NvimView/Support/NvimViewSupport.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 135,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:\">\n </FileRef"
},
{
"path": "NvimView/Support/NvimViewSupport.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "NvimView/Support/NvimViewSupport.xcodeproj/xcshareddata/xcschemes/MinimalNvimViewDemo.xcscheme",
"chars": 2938,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"2600\"\n version = \"1.7\">\n <BuildAction\n "
},
{
"path": "NvimView/Tests/NvimViewTests/CellAttributesCollectionTest.swift",
"chars": 2251,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Nimble\nimport XCTest\n\n@testable"
},
{
"path": "NvimView/Tests/NvimViewTests/NimbleCommons.swift",
"chars": 806,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Nimble\n\n// I don't know why the"
},
{
"path": "NvimView/Tests/NvimViewTests/TypesetterTest.swift",
"chars": 20946,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Nimble\nimport XCTest\n\n@testable"
},
{
"path": "NvimView/Tests/NvimViewTests/UGridTest.swift",
"chars": 4296,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Nimble\nimport XCTest\n\n@testable"
},
{
"path": "README.md",
"chars": 3008,
"preview": "# VimR — Neovim GUI for macOS\n\n[Download](https://github.com/qvacua/vimr/releases) • [Documentation](https://github.com/"
},
{
"path": "Tabs/.gitignore",
"chars": 53,
"preview": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\nxcuserdata/\n"
},
{
"path": "Tabs/Package.swift",
"chars": 723,
"preview": "// swift-tools-version: 6.0\n\nimport PackageDescription\n\nlet package = Package(\n name: \"Tabs\",\n platforms: [.macOS(.v14"
},
{
"path": "Tabs/README.md",
"chars": 39,
"preview": "# Tabs\n\nA description of this package.\n"
},
{
"path": "Tabs/Sources/Tabs/DraggingSingleRowStackView.swift",
"chars": 4586,
"preview": "//\n// DraggingSingleRowStackView.swift\n// Analysis\n//\n// Created by Mark Onyschuk on 2017-02-02.\n// Copyright © 2017"
},
{
"path": "Tabs/Sources/Tabs/HorizontalOnlyScrollView.swift",
"chars": 1150,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n\nfinal class HorizontalOnlyScrollView:"
},
{
"path": "Tabs/Sources/Tabs/Tab.swift",
"chars": 6484,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport MaterialIcons\n\nstruct TabPositi"
},
{
"path": "Tabs/Sources/Tabs/TabBar.swift",
"chars": 4049,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport PureLayout\n\npublic protocol Tab"
},
{
"path": "Tabs/Sources/Tabs/Theme.swift",
"chars": 2181,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport MaterialIcons\n\npublic struct Th"
},
{
"path": "Tabs/Support/TabsSupport/AppDelegate.swift",
"chars": 2082,
"preview": "//\n// AppDelegate.swift\n// TabsSupport\n//\n// Created by Tae Won Ha on 22.11.20.\n//\n\nimport Cocoa\nimport PureLayout\nim"
},
{
"path": "Tabs/Support/TabsSupport/Assets.xcassets/AccentColor.colorset/Contents.json",
"chars": 123,
"preview": "{\n \"colors\" : [\n {\n \"idiom\" : \"universal\"\n }\n ],\n \"info\" : {\n \"author\" : \"xcode\",\n \"version\" : 1\n }"
},
{
"path": "Tabs/Support/TabsSupport/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 904,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"mac\",\n \"scale\" : \"1x\",\n \"size\" : \"16x16\"\n },\n {\n \"idiom\" : "
},
{
"path": "Tabs/Support/TabsSupport/Assets.xcassets/Contents.json",
"chars": 63,
"preview": "{\n \"info\" : {\n \"author\" : \"xcode\",\n \"version\" : 1\n }\n}\n"
},
{
"path": "Tabs/Support/TabsSupport/Base.lproj/MainMenu.xib",
"chars": 50798,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "Tabs/Support/TabsSupport/Info.plist",
"chars": 970,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Tabs/Support/TabsSupport.xcodeproj/project.pbxproj",
"chars": 12201,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "VimR/Dev.xcconfig",
"chars": 74,
"preview": "VIMR_DISPLAY_NAME = VimR-dev\nVIMR_BUNDLE_IDENTIFIER = com.qvacua.VimR.dev\n"
},
{
"path": "VimR/Release.xcconfig",
"chars": 66,
"preview": "VIMR_DISPLAY_NAME = VimR\nVIMR_BUNDLE_IDENTIFIER = com.qvacua.VimR\n"
},
{
"path": "VimR/VimR/AdvancedPrefReducer.swift",
"chars": 806,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\n\nfinal class AdvancedPrefReducer:"
},
{
"path": "VimR/VimR/AdvencedPref.swift",
"chars": 7676,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport PureLayout\n\nfinal class Advance"
},
{
"path": "VimR/VimR/AppDelegate.swift",
"chars": 17621,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Commons\nimport CommonsObjC\nimpo"
},
{
"path": "VimR/VimR/AppDelegateReducer.swift",
"chars": 2686,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\n\nfinal class AppDelegateReducer: "
},
{
"path": "VimR/VimR/AppKitCommons.swift",
"chars": 4587,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n@preconcurrency import Down\n\nextension"
},
{
"path": "VimR/VimR/AppearancePref.swift",
"chars": 16778,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport NvimView\nimport PureLayout\n\nfin"
},
{
"path": "VimR/VimR/AppearancePrefReducer.swift",
"chars": 1464,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\n\nfinal class AppearancePrefReduce"
},
{
"path": "VimR/VimR/Application.swift",
"chars": 685,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Sparkle\n\nfinal class Applicatio"
},
{
"path": "VimR/VimR/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1218,
"preview": "{\n \"images\" : [\n {\n \"size\" : \"16x16\",\n \"idiom\" : \"mac\",\n \"filename\" : \"icon_16x16.png\",\n \"scale\""
},
{
"path": "VimR/VimR/Base.lproj/Credits.rtf",
"chars": 4197,
"preview": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2821\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fswiss\\fcharset0 Helvetica;\\f1\\fswiss"
},
{
"path": "VimR/VimR/Base.lproj/FileBrowserMenu.xib",
"chars": 3985,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "VimR/VimR/Base.lproj/MainMenu.xib",
"chars": 23262,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "VimR/VimR/Base.lproj/MainWindow.xib",
"chars": 1887,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "VimR/VimR/Base.lproj/OpenQuicklyWindow.xib",
"chars": 2114,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "VimR/VimR/Base.lproj/PrefWindow.xib",
"chars": 1760,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3"
},
{
"path": "VimR/VimR/Bridge.h",
"chars": 131,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\n#import \"ScoredUrl.h\"\n#import \"FileItem+CoreDataPro"
},
{
"path": "VimR/VimR/BufferList.swift",
"chars": 5968,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Combine\nimport Commons\nimport N"
},
{
"path": "VimR/VimR/BufferListReducer.swift",
"chars": 561,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\n\nfinal class BuffersListReducer: "
},
{
"path": "VimR/VimR/Context.swift",
"chars": 4842,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\nimport os\n\nfinal class ReduxConte"
},
{
"path": "VimR/VimR/CoreDataStack.swift",
"chars": 2911,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Commons\nimport CoreData\nimport Foundation\nim"
},
{
"path": "VimR/VimR/CssUtils.swift",
"chars": 1811,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\n\nfinal class CssUtils {\n // swiftlint"
},
{
"path": "VimR/VimR/DefaultShortcuts.swift",
"chars": 4275,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\n@preconcurrency import ShortcutRe"
},
{
"path": "VimR/VimR/Defs.swift",
"chars": 404,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Commons\nimport Foundation\n\nenum Defs {\n sta"
},
{
"path": "VimR/VimR/FileBrowser.swift",
"chars": 5908,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Cocoa\nimport Commons\nimport MaterialIcons\nim"
},
{
"path": "VimR/VimR/FileBrowserReducer.swift",
"chars": 821,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Foundation\n\nfinal class FileBrowserReducer: "
},
{
"path": "VimR/VimR/FileItem+CoreDataClass.h",
"chars": 342,
"preview": "//\n// FileItem+CoreDataClass.h\n// VimR\n//\n// Created by Tae Won Ha on 18.01.20.\n// Copyright © 2020 Tae Won Ha. All "
},
{
"path": "VimR/VimR/FileItem+CoreDataClass.m",
"chars": 211,
"preview": "//\n// FileItem+CoreDataClass.m\n// VimR\n//\n// Created by Tae Won Ha on 18.01.20.\n// Copyright © 2020 Tae Won Ha. All "
},
{
"path": "VimR/VimR/FileMonitor.swift",
"chars": 1610,
"preview": "/**\n * Tae Won Ha - http://taewon.de - @hataewon\n * See LICENSE\n */\n\nimport Commons\nimport EonilFSEvents\nimport Foundati"
}
]
// ... and 176 more files (download for full content)
About this extraction
This page contains the full source code of the qvacua/vimr GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 376 files (5.6 MB), approximately 1.5M tokens, and a symbol index with 19 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.