Improve JSON editor for iOS
This commit is contained in:
@@ -29,26 +29,30 @@
|
||||
}
|
||||
}
|
||||
} else {
|
||||
viewBuilder {
|
||||
if readOnly {
|
||||
TextEditor(text: .constant(viewModel.profileContent))
|
||||
} else {
|
||||
TextEditor(text: $viewModel.profileContent)
|
||||
}
|
||||
}
|
||||
.font(Font.system(.caption2, design: .monospaced))
|
||||
.autocorrectionDisabled(true)
|
||||
.textContentType(.init(rawValue: ""))
|
||||
#if os(iOS)
|
||||
.keyboardType(.asciiCapable)
|
||||
.textInputAutocapitalization(.none)
|
||||
.background(Color(UIColor.secondarySystemGroupedBackground))
|
||||
#elseif os(macOS)
|
||||
.padding()
|
||||
#endif
|
||||
RunestoneTextView(
|
||||
text: readOnly ? .constant(viewModel.profileContent) : $viewModel.profileContent,
|
||||
isEditable: !readOnly
|
||||
)
|
||||
.onChangeCompat(of: viewModel.profileContent) {
|
||||
viewModel.markAsChanged()
|
||||
}
|
||||
#elseif os(macOS)
|
||||
viewBuilder {
|
||||
if readOnly {
|
||||
TextEditor(text: .constant(viewModel.profileContent))
|
||||
} else {
|
||||
TextEditor(text: $viewModel.profileContent)
|
||||
}
|
||||
}
|
||||
.font(Font.system(.caption2, design: .monospaced))
|
||||
.autocorrectionDisabled(true)
|
||||
.textContentType(.init(rawValue: ""))
|
||||
.padding()
|
||||
.onChangeCompat(of: viewModel.profileContent) {
|
||||
viewModel.markAsChanged()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
.alertBinding($viewModel.alert)
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
#if os(iOS)
|
||||
import Runestone
|
||||
import UIKit
|
||||
|
||||
final class ProfileEditorTheme: Theme {
|
||||
let font: UIFont = .monospacedSystemFont(ofSize: 14, weight: .regular)
|
||||
let textColor: UIColor = .label
|
||||
|
||||
let gutterBackgroundColor: UIColor = .secondarySystemBackground
|
||||
let gutterHairlineColor: UIColor = .separator
|
||||
|
||||
let lineNumberColor: UIColor = .secondaryLabel
|
||||
let lineNumberFont: UIFont = .monospacedSystemFont(ofSize: 14, weight: .regular)
|
||||
|
||||
let selectedLineBackgroundColor: UIColor = .systemFill
|
||||
let selectedLinesLineNumberColor: UIColor = .label
|
||||
let selectedLinesGutterBackgroundColor: UIColor = .secondarySystemBackground
|
||||
|
||||
let invisibleCharactersColor: UIColor = .tertiaryLabel
|
||||
|
||||
let pageGuideHairlineColor: UIColor = .separator
|
||||
let pageGuideBackgroundColor: UIColor = .secondarySystemBackground
|
||||
|
||||
let markedTextBackgroundColor: UIColor = .systemFill
|
||||
let markedTextBackgroundCornerRadius: CGFloat = 4
|
||||
|
||||
func textColor(for rawHighlightName: String) -> UIColor? {
|
||||
guard let highlightName = HighlightName(rawHighlightName) else {
|
||||
return nil
|
||||
}
|
||||
switch highlightName {
|
||||
case .comment:
|
||||
return .secondaryLabel
|
||||
case .property:
|
||||
return .systemCyan
|
||||
case .string:
|
||||
return .systemGreen
|
||||
case .number:
|
||||
return .systemOrange
|
||||
case .constantBuiltin:
|
||||
return .systemPurple
|
||||
case .error:
|
||||
return .systemRed
|
||||
}
|
||||
}
|
||||
|
||||
func fontTraits(for _: String) -> FontTraits {
|
||||
[]
|
||||
}
|
||||
}
|
||||
|
||||
private enum HighlightName: String {
|
||||
case comment
|
||||
case property
|
||||
case string
|
||||
case number
|
||||
case constantBuiltin = "constant.builtin"
|
||||
case error
|
||||
|
||||
init?(_ rawHighlightName: String) {
|
||||
var components = rawHighlightName.split(separator: ".")
|
||||
while !components.isEmpty {
|
||||
let candidateRawHighlightName = components.joined(separator: ".")
|
||||
if let highlightName = Self(rawValue: candidateRawHighlightName) {
|
||||
self = highlightName
|
||||
return
|
||||
}
|
||||
components.removeLast()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
#if os(iOS)
|
||||
import Runestone
|
||||
import SwiftUI
|
||||
import TreeSitterJSON5Runestone
|
||||
|
||||
struct RunestoneTextView: UIViewRepresentable {
|
||||
@Binding var text: String
|
||||
let isEditable: Bool
|
||||
|
||||
func makeUIView(context: Context) -> TextView {
|
||||
let textView = TextView()
|
||||
|
||||
textView.showLineNumbers = true
|
||||
textView.isLineWrappingEnabled = false
|
||||
textView.showTabs = false
|
||||
textView.showSpaces = false
|
||||
textView.showLineBreaks = false
|
||||
textView.showSoftLineBreaks = false
|
||||
textView.showNonBreakingSpaces = false
|
||||
|
||||
textView.autocorrectionType = .no
|
||||
textView.autocapitalizationType = .none
|
||||
textView.smartDashesType = .no
|
||||
textView.smartQuotesType = .no
|
||||
textView.smartInsertDeleteType = .no
|
||||
|
||||
textView.backgroundColor = .secondarySystemGroupedBackground
|
||||
textView.contentInsetAdjustmentBehavior = .always
|
||||
textView.alwaysBounceVertical = true
|
||||
|
||||
textView.kern = 0.3
|
||||
textView.lineHeightMultiplier = 1.3
|
||||
|
||||
textView.characterPairs = [
|
||||
BasicCharacterPair(leading: "{", trailing: "}"),
|
||||
BasicCharacterPair(leading: "[", trailing: "]"),
|
||||
BasicCharacterPair(leading: "\"", trailing: "\""),
|
||||
]
|
||||
|
||||
let theme = ProfileEditorTheme()
|
||||
let state = TextViewState(text: text, theme: theme, language: .json5)
|
||||
textView.setState(state)
|
||||
|
||||
textView.isEditable = isEditable
|
||||
textView.editorDelegate = context.coordinator
|
||||
|
||||
return textView
|
||||
}
|
||||
|
||||
func updateUIView(_ textView: TextView, context _: Context) {
|
||||
if textView.text != text {
|
||||
textView.text = text
|
||||
}
|
||||
if textView.isEditable != isEditable {
|
||||
textView.isEditable = isEditable
|
||||
}
|
||||
}
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(self)
|
||||
}
|
||||
|
||||
final class Coordinator: TextViewDelegate {
|
||||
var parent: RunestoneTextView
|
||||
|
||||
init(_ parent: RunestoneTextView) {
|
||||
self.parent = parent
|
||||
}
|
||||
|
||||
func textViewDidChange(_ textView: TextView) {
|
||||
parent.text = textView.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class BasicCharacterPair: CharacterPair {
|
||||
let leading: String
|
||||
let trailing: String
|
||||
|
||||
init(leading: String, trailing: String) {
|
||||
self.leading = leading
|
||||
self.trailing = trailing
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
.build/
|
||||
.swiftpm/
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "Runestone",
|
||||
"repositoryURL": "https://github.com/simonbs/Runestone",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "1fad339aab99cf2136ce6bf8c32da3265b2e85e5",
|
||||
"version": "0.5.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "TreeSitter",
|
||||
"repositoryURL": "https://github.com/tree-sitter/tree-sitter",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "98be227227af10cc7a269cb3ffb23686c0610b17",
|
||||
"version": "0.20.9"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// swift-tools-version:5.5
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "TreeSitterJSON5",
|
||||
platforms: [
|
||||
.iOS(.v14), .macCatalyst(.v14),
|
||||
],
|
||||
products: [
|
||||
.library(name: "TreeSitterJSON5", targets: ["TreeSitterJSON5"]),
|
||||
.library(name: "TreeSitterJSON5Queries", targets: ["TreeSitterJSON5Queries"]),
|
||||
.library(name: "TreeSitterJSON5Runestone", targets: ["TreeSitterJSON5Runestone"]),
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/simonbs/Runestone", from: "0.3.0"),
|
||||
],
|
||||
targets: [
|
||||
.target(name: "TreeSitterJSON5", cSettings: [.headerSearchPath("src")]),
|
||||
.target(name: "TreeSitterJSON5Queries", resources: [.copy("highlights.scm"), .copy("injections.scm")]),
|
||||
.target(name: "TreeSitterJSON5Runestone", dependencies: ["Runestone", "TreeSitterJSON5", "TreeSitterJSON5Queries"]),
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,3 @@
|
||||
# TreeSitterJSON5
|
||||
|
||||
Copied from https://github.com/Lakr233/FlowDown
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct TSLanguage TSLanguage;
|
||||
const TSLanguage *tree_sitter_json5(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,223 @@
|
||||
#ifndef TREE_SITTER_PARSER_H_
|
||||
#define TREE_SITTER_PARSER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ts_builtin_sym_error ((TSSymbol)-1)
|
||||
#define ts_builtin_sym_end 0
|
||||
#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024
|
||||
|
||||
typedef uint16_t TSStateId;
|
||||
|
||||
#ifndef TREE_SITTER_API_H_
|
||||
typedef uint16_t TSSymbol;
|
||||
typedef uint16_t TSFieldId;
|
||||
typedef struct TSLanguage TSLanguage;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
TSFieldId field_id;
|
||||
uint8_t child_index;
|
||||
bool inherited;
|
||||
} TSFieldMapEntry;
|
||||
|
||||
typedef struct {
|
||||
uint16_t index;
|
||||
uint16_t length;
|
||||
} TSFieldMapSlice;
|
||||
|
||||
typedef struct {
|
||||
bool visible;
|
||||
bool named;
|
||||
bool supertype;
|
||||
} TSSymbolMetadata;
|
||||
|
||||
typedef struct TSLexer TSLexer;
|
||||
|
||||
struct TSLexer {
|
||||
int32_t lookahead;
|
||||
TSSymbol result_symbol;
|
||||
void (*advance)(TSLexer *, bool);
|
||||
void (*mark_end)(TSLexer *);
|
||||
uint32_t (*get_column)(TSLexer *);
|
||||
bool (*is_at_included_range_start)(const TSLexer *);
|
||||
bool (*eof)(const TSLexer *);
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
TSParseActionTypeShift,
|
||||
TSParseActionTypeReduce,
|
||||
TSParseActionTypeAccept,
|
||||
TSParseActionTypeRecover,
|
||||
} TSParseActionType;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t type;
|
||||
TSStateId state;
|
||||
bool extra;
|
||||
bool repetition;
|
||||
} shift;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t child_count;
|
||||
TSSymbol symbol;
|
||||
int16_t dynamic_precedence;
|
||||
uint16_t production_id;
|
||||
} reduce;
|
||||
uint8_t type;
|
||||
} TSParseAction;
|
||||
|
||||
typedef struct {
|
||||
uint16_t lex_state;
|
||||
uint16_t external_lex_state;
|
||||
} TSLexMode;
|
||||
|
||||
typedef union {
|
||||
TSParseAction action;
|
||||
struct {
|
||||
uint8_t count;
|
||||
bool reusable;
|
||||
} entry;
|
||||
} TSParseActionEntry;
|
||||
|
||||
struct TSLanguage {
|
||||
uint32_t version;
|
||||
uint32_t symbol_count;
|
||||
uint32_t alias_count;
|
||||
uint32_t token_count;
|
||||
uint32_t external_token_count;
|
||||
uint32_t state_count;
|
||||
uint32_t large_state_count;
|
||||
uint32_t production_id_count;
|
||||
uint32_t field_count;
|
||||
uint16_t max_alias_sequence_length;
|
||||
const uint16_t *parse_table;
|
||||
const uint16_t *small_parse_table;
|
||||
const uint32_t *small_parse_table_map;
|
||||
const TSParseActionEntry *parse_actions;
|
||||
const char * const *symbol_names;
|
||||
const char * const *field_names;
|
||||
const TSFieldMapSlice *field_map_slices;
|
||||
const TSFieldMapEntry *field_map_entries;
|
||||
const TSSymbolMetadata *symbol_metadata;
|
||||
const TSSymbol *public_symbol_map;
|
||||
const uint16_t *alias_map;
|
||||
const TSSymbol *alias_sequences;
|
||||
const TSLexMode *lex_modes;
|
||||
bool (*lex_fn)(TSLexer *, TSStateId);
|
||||
bool (*keyword_lex_fn)(TSLexer *, TSStateId);
|
||||
TSSymbol keyword_capture_token;
|
||||
struct {
|
||||
const bool *states;
|
||||
const TSSymbol *symbol_map;
|
||||
void *(*create)(void);
|
||||
void (*destroy)(void *);
|
||||
bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist);
|
||||
unsigned (*serialize)(void *, char *);
|
||||
void (*deserialize)(void *, const char *, unsigned);
|
||||
} external_scanner;
|
||||
};
|
||||
|
||||
/*
|
||||
* Lexer Macros
|
||||
*/
|
||||
|
||||
#define START_LEXER() \
|
||||
bool result = false; \
|
||||
bool skip = false; \
|
||||
bool eof = false; \
|
||||
int32_t lookahead; \
|
||||
goto start; \
|
||||
next_state: \
|
||||
lexer->advance(lexer, skip); \
|
||||
start: \
|
||||
skip = false; \
|
||||
lookahead = lexer->lookahead;
|
||||
|
||||
#define ADVANCE(state_value) \
|
||||
{ \
|
||||
state = state_value; \
|
||||
goto next_state; \
|
||||
}
|
||||
|
||||
#define SKIP(state_value) \
|
||||
{ \
|
||||
skip = true; \
|
||||
state = state_value; \
|
||||
goto next_state; \
|
||||
}
|
||||
|
||||
#define ACCEPT_TOKEN(symbol_value) \
|
||||
result = true; \
|
||||
lexer->result_symbol = symbol_value; \
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
#define END_STATE() return result;
|
||||
|
||||
/*
|
||||
* Parse Table Macros
|
||||
*/
|
||||
|
||||
#define SMALL_STATE(id) id - LARGE_STATE_COUNT
|
||||
|
||||
#define STATE(id) id
|
||||
|
||||
#define ACTIONS(id) id
|
||||
|
||||
#define SHIFT(state_value) \
|
||||
{{ \
|
||||
.shift = { \
|
||||
.type = TSParseActionTypeShift, \
|
||||
.state = state_value \
|
||||
} \
|
||||
}}
|
||||
|
||||
#define SHIFT_REPEAT(state_value) \
|
||||
{{ \
|
||||
.shift = { \
|
||||
.type = TSParseActionTypeShift, \
|
||||
.state = state_value, \
|
||||
.repetition = true \
|
||||
} \
|
||||
}}
|
||||
|
||||
#define SHIFT_EXTRA() \
|
||||
{{ \
|
||||
.shift = { \
|
||||
.type = TSParseActionTypeShift, \
|
||||
.extra = true \
|
||||
} \
|
||||
}}
|
||||
|
||||
#define REDUCE(symbol_val, child_count_val, ...) \
|
||||
{{ \
|
||||
.reduce = { \
|
||||
.type = TSParseActionTypeReduce, \
|
||||
.symbol = symbol_val, \
|
||||
.child_count = child_count_val, \
|
||||
__VA_ARGS__ \
|
||||
}, \
|
||||
}}
|
||||
|
||||
#define RECOVER() \
|
||||
{{ \
|
||||
.type = TSParseActionTypeRecover \
|
||||
}}
|
||||
|
||||
#define ACCEPT_INPUT() \
|
||||
{{ \
|
||||
.type = TSParseActionTypeAccept \
|
||||
}}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TREE_SITTER_PARSER_H_
|
||||
@@ -0,0 +1,17 @@
|
||||
import Foundation
|
||||
|
||||
public enum Query {
|
||||
public static var highlightsFileURL: URL {
|
||||
url(named: "highlights")
|
||||
}
|
||||
|
||||
public static var injectionsFileURL: URL {
|
||||
url(named: "injections")
|
||||
}
|
||||
}
|
||||
|
||||
private extension Query {
|
||||
static func url(named filename: String) -> URL {
|
||||
Bundle.module.url(forResource: filename, withExtension: "scm")!
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
(number) @number
|
||||
|
||||
(comment) @comment
|
||||
|
||||
(member name: (_) @property)
|
||||
|
||||
(member value: (string) @string)
|
||||
(member value: (number) @number)
|
||||
(member value: ["true" "false" "null"] @constant.builtin)
|
||||
|
||||
(array ((string) @string))
|
||||
(array (number) @number)
|
||||
(array ["true" "false" "null"] @constant.builtin)
|
||||
|
||||
(ERROR) @error
|
||||
@@ -0,0 +1 @@
|
||||
(comment) @comment
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import Runestone
|
||||
|
||||
public extension TreeSitterIndentationScopes {
|
||||
static var json5: TreeSitterIndentationScopes {
|
||||
TreeSitterIndentationScopes(indent: ["object", "array"], outdent: ["}", "]"])
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import Runestone
|
||||
import TreeSitterJSON5
|
||||
import TreeSitterJSON5Queries
|
||||
|
||||
public extension TreeSitterLanguage {
|
||||
static var json5: TreeSitterLanguage {
|
||||
let highlightsQuery = TreeSitterLanguage.Query(contentsOf: TreeSitterJSON5Queries.Query.highlightsFileURL)
|
||||
let injectionsQuery = TreeSitterLanguage.Query(contentsOf: TreeSitterJSON5Queries.Query.injectionsFileURL)
|
||||
return TreeSitterLanguage(tree_sitter_json5(), highlightsQuery: highlightsQuery, injectionsQuery: injectionsQuery, indentationScopes: .json5)
|
||||
}
|
||||
}
|
||||
@@ -1232,6 +1232,7 @@
|
||||
}
|
||||
},
|
||||
"Page" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
@@ -1486,6 +1487,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Share QR Code" : {
|
||||
|
||||
},
|
||||
"Share URL as QR Code" : {
|
||||
"localizations" : {
|
||||
@@ -1752,6 +1756,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Update Failed" : {
|
||||
|
||||
},
|
||||
"Uplink" : {
|
||||
"localizations" : {
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
3A017F922A4AB2E4009149FA /* GRDB in Frameworks */ = {isa = PBXBuildFile; productRef = 3A017F912A4AB2E4009149FA /* GRDB */; };
|
||||
3A096F8F2A4ED3DE00D4A2ED /* Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 3A096F862A4ED3DE00D4A2ED /* Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
3A2E87F22ED5A91100644195 /* Runestone in Frameworks */ = {isa = PBXBuildFile; productRef = 3A2E87F12ED5A91100644195 /* Runestone */; };
|
||||
3A2E87FB2ED5ABDA00644195 /* TreeSitterJSON5Runestone in Frameworks */ = {isa = PBXBuildFile; productRef = 3A2E87FA2ED5ABDA00644195 /* TreeSitterJSON5Runestone */; };
|
||||
3A3AA7FC2A4EFDAE002F78AB /* Library.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC211D2A459B4700A63465 /* Library.framework */; };
|
||||
3A3AA7FF2A4EFDB3002F78AB /* Library.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC211D2A459B4700A63465 /* Library.framework */; };
|
||||
3A3DEBEB2A4FFE2D00373BF4 /* AppIntents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A3DEBE62A4FFA6000373BF4 /* AppIntents.framework */; };
|
||||
@@ -534,6 +536,8 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3A4EAD1B2A4FEB02005435B3 /* Library.framework in Frameworks */,
|
||||
3A2E87FB2ED5ABDA00644195 /* TreeSitterJSON5Runestone in Frameworks */,
|
||||
3A2E87F22ED5A91100644195 /* Runestone in Frameworks */,
|
||||
3A4A020D2B53E3DC004EFB87 /* QRCode in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -754,6 +758,8 @@
|
||||
name = ApplicationLibrary;
|
||||
packageProductDependencies = (
|
||||
3A4A020C2B53E3DC004EFB87 /* QRCode */,
|
||||
3A2E87F12ED5A91100644195 /* Runestone */,
|
||||
3A2E87FA2ED5ABDA00644195 /* TreeSitterJSON5Runestone */,
|
||||
);
|
||||
productName = ApplicationLibrary;
|
||||
productReference = 3A4EAD102A4FEAE6005435B3 /* ApplicationLibrary.framework */;
|
||||
@@ -1058,6 +1064,8 @@
|
||||
3A017F902A4AB2E4009149FA /* XCRemoteSwiftPackageReference "GRDB" */,
|
||||
3A57DF3A2A4D705000690BC5 /* XCRemoteSwiftPackageReference "MacControlCenterUI" */,
|
||||
3A4A020B2B53E3DC004EFB87 /* XCRemoteSwiftPackageReference "qrcode" */,
|
||||
3A2E87F02ED5A91100644195 /* XCRemoteSwiftPackageReference "Runestone" */,
|
||||
3A2E87F92ED5ABCF00644195 /* XCLocalSwiftPackageReference "Frameworks/TreeSitterJSON5" */,
|
||||
);
|
||||
productRefGroup = 3AEC20C72A45991900A63465 /* Products */;
|
||||
projectDirPath = "";
|
||||
@@ -2553,6 +2561,13 @@
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCLocalSwiftPackageReference section */
|
||||
3A2E87F92ED5ABCF00644195 /* XCLocalSwiftPackageReference "Frameworks/TreeSitterJSON5" */ = {
|
||||
isa = XCLocalSwiftPackageReference;
|
||||
relativePath = Frameworks/TreeSitterJSON5;
|
||||
};
|
||||
/* End XCLocalSwiftPackageReference section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
3A017F902A4AB2E4009149FA /* XCRemoteSwiftPackageReference "GRDB" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
@@ -2562,6 +2577,14 @@
|
||||
minimumVersion = 6.15.1;
|
||||
};
|
||||
};
|
||||
3A2E87F02ED5A91100644195 /* XCRemoteSwiftPackageReference "Runestone" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/simonbs/Runestone";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 0.5.1;
|
||||
};
|
||||
};
|
||||
3A4A020B2B53E3DC004EFB87 /* XCRemoteSwiftPackageReference "qrcode" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/dagronf/qrcode.git";
|
||||
@@ -2594,6 +2617,16 @@
|
||||
package = 3A017F902A4AB2E4009149FA /* XCRemoteSwiftPackageReference "GRDB" */;
|
||||
productName = GRDB;
|
||||
};
|
||||
3A2E87F12ED5A91100644195 /* Runestone */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 3A2E87F02ED5A91100644195 /* XCRemoteSwiftPackageReference "Runestone" */;
|
||||
productName = Runestone;
|
||||
};
|
||||
3A2E87FA2ED5ABDA00644195 /* TreeSitterJSON5Runestone */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 3A2E87F92ED5ABCF00644195 /* XCLocalSwiftPackageReference "Frameworks/TreeSitterJSON5" */;
|
||||
productName = TreeSitterJSON5Runestone;
|
||||
};
|
||||
3A4A020C2B53E3DC004EFB87 /* QRCode */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 3A4A020B2B53E3DC004EFB87 /* XCRemoteSwiftPackageReference "qrcode" */;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"originHash" : "82fb479ec8c73c3348b93e33a9102fc692bb5a0a0d6f14beb4c5f31445c36e81",
|
||||
"originHash" : "48cbd083120736a1a1ce4b717dcbfdb7900aa5e2aa21991865021fb98adc2093",
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "binarycodable",
|
||||
@@ -46,6 +46,15 @@
|
||||
"version" : "17.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "runestone",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/simonbs/Runestone",
|
||||
"state" : {
|
||||
"revision" : "1fad339aab99cf2136ce6bf8c32da3265b2e85e5",
|
||||
"version" : "0.5.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-qrcode-generator",
|
||||
"kind" : "remoteSourceControl",
|
||||
@@ -63,6 +72,15 @@
|
||||
"revision" : "96361ba7f9dce5184d95aba8ea90d9faa4acabb2",
|
||||
"version" : "1.6.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "tree-sitter",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/tree-sitter/tree-sitter",
|
||||
"state" : {
|
||||
"revision" : "98be227227af10cc7a269cb3ffb23686c0610b17",
|
||||
"version" : "0.20.9"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 3
|
||||
|
||||
Reference in New Issue
Block a user