Skip to content

Commit

Permalink
feat: add support for symbol reference
Browse files Browse the repository at this point in the history
Keyboard symbol table has a new references section where there are symbols that could be referenced

#17
  • Loading branch information
Build Pipeline committed Mar 13, 2023
1 parent 39fed2e commit f74a6dc
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct ChoiceKeyButton: View {
@Environment(\.colorScheme) var colorScheme

// @State private var showingSheet = false
@State private var selection: String?
@State private var selection: Symbol?

var symbol:Symbol
var onPressSymbol: (Symbol) -> Void
Expand All @@ -34,7 +34,15 @@ struct ChoiceKeyButton: View {
var body: some View {
Button {
// showingSheet.toggle()
presentViewOnRootController( ChoiceView( symbol: symbol, selection: $selection ) )
if let choices = symbol.additionalValues?.map({
if let ref = try? Symbol.matchRef(in: $0 ), let choice = Symbol.references?.first(where: { s in s.id == ref }) {
return choice
}
return Symbol( id: symbol.id, value: String(format: symbol.value, $0 ) )
}) {
presentViewOnRootController( ChoiceView( title: symbol.id, choices: choices, selection: $selection ) )

}
}
label: {
Label(symbol.id, systemImage: "list.bullet")
Expand All @@ -45,12 +53,8 @@ struct ChoiceKeyButton: View {
.onChange(of: selection) { _ in

if let selection {

let value = String(format: symbol.value, selection )

let symbol = Symbol( id: symbol.id, value: value )

onPressSymbol( symbol )
onPressSymbol( selection )

}
}
Expand All @@ -63,12 +67,9 @@ struct ChoiceKeyButton: View {
struct ChoiceView: View {
@Environment(\.dismiss) var dismiss

var symbol: Symbol
@Binding var selection: String?

private var items: [String] {
symbol.additionalValues ?? []
}
var title: String
var choices: [Symbol]
@Binding var selection: Symbol?

private func Navigation( content: () -> some View ) -> some View {
if #available(iOS 16.0, *) {
Expand All @@ -82,20 +83,20 @@ struct ChoiceView: View {
var body: some View {
Navigation {

List(items, id: \.self, selection: $selection) { name in
Text(name)
List(choices, id: \.self, selection: $selection) {
Text($0.id)
}
.onChange(of: selection) { _ in
dismiss()
}
.navigationTitle( symbol.id )
.navigationTitle( title )
.toolbar {
ToolbarItem( placement: .navigationBarTrailing ) {
Button {
dismiss()
}
label: {
Label(symbol.id, systemImage: "xmark")
Label(title, systemImage: "xmark")
.labelStyle( .iconOnly )
}
}
Expand Down
63 changes: 36 additions & 27 deletions PlantUMLKeyboard/Sources/PlantUMLKeyboard/PlantUMLSymbol+Data.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,40 @@
import Foundation
import UIKit
import PlantUMLFramework


//
// LOAD JSON DATA
//
let plantUMLSymbols: Array<PlantUMLSymbolGroup> = {

guard let path = Bundle.module.path(forResource: "plantuml_keyboard_data", ofType: "json") else {
return []
}

let decoder = JSONDecoder()

do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)

let result = try decoder.decode(Array<PlantUMLSymbolGroup>.self, from: data)

Symbol.references = result.first { $0.name == "references" }

return result.filter { $0.name != "references" }

} catch {
logger.error( "\(error.localizedDescription)")
return []
}

}()

// /////////////////////////////////////////////////////////////////
// @resultBuilder based implementation
// /////////////////////////////////////////////////////////////////


//
// MARK: COMMON DIAGRAMS
//
Expand Down Expand Up @@ -37,10 +71,10 @@ fileprivate func common_symbols() -> [[Symbol]] {

}


//
// MARK: SEQUENCE DIAGRAMS
//

@Symbol.LineBuilder
fileprivate func sequence_symbols() -> [[Symbol]] {

Expand Down Expand Up @@ -99,8 +133,6 @@ fileprivate func sequence_symbols() -> [[Symbol]] {
//
// MARK: DEPLOYMENT DIAGRAMS
//


@Symbol.LineBuilder
fileprivate func deployment_symbols() -> [[Symbol]] {

Expand Down Expand Up @@ -162,31 +194,8 @@ fileprivate func deployment_symbols() -> [[Symbol]] {


let plantUMLSymbols_static = [

PlantUMLSymbolGroup( name: "general", rows: common_symbols() ),
PlantUMLSymbolGroup( name: "sequence", rows: sequence_symbols() ),
PlantUMLSymbolGroup( name: "deployment", rows: deployment_symbols() ),
]


let plantUMLSymbols: Array<PlantUMLSymbolGroup> = {

guard let path = Bundle.module.path(forResource: "plantuml_keyboard_data", ofType: "json") else {
return []
}

let decoder = JSONDecoder()

do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)

let result = try decoder.decode(Array<PlantUMLSymbolGroup>.self, from: data)

return result

} catch {
logger.error( "\(error.localizedDescription)")
return []
}

}()
105 changes: 69 additions & 36 deletions PlantUMLKeyboard/Sources/PlantUMLKeyboard/PlantUMLSymbol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,61 +7,94 @@

import UIKit
import LineEditor
import PlantUMLFramework

public struct Symbol : Decodable, Identifiable, CustomStringConvertible, LineEditorKeyboardSymbol {

public struct Symbol : Decodable, Identifiable, Equatable, Hashable, CustomStringConvertible, LineEditorKeyboardSymbol {
enum CodingKeys: String, CodingKey {
case id
case value
case additionalValues = "additional"
case type
}
public var description: String { value }

public var id:String
private var _value:String?
public private(set) var additionalValues:[String]?
public var type = "string"

public var value: String {
get { _value ?? id }
}

// var additionalValues: [String]? {
// get { _additionalValues }
// }
case id
case value
case additionalValues = "additional"
case type
}

public var id:String
private var _value:String?
public private(set) var additionalValues:[String]?
public var type = "string"

public var value: String { get { _value ?? id } }
public var description: String { id }

public init( id:String, value:String? = nil, additionalValues: [String]? = nil) {
self.id = id
self._value = value
self.additionalValues = additionalValues
}
static var references: PlantUMLSymbolGroup?

public init( id:String, value:String? = nil, additionalValues: [String]? = nil ) {
self.id = id
self._value = value
self.additionalValues = additionalValues
}

public init(from decoder: Decoder) throws {

let container = try decoder.container(keyedBy: CodingKeys.self )

self.id = try container.decode(String.self, forKey: CodingKeys.id)
self._value = try container.decodeIfPresent(String.self, forKey: CodingKeys.value)
self.additionalValues = try container.decodeIfPresent([String].self, forKey: CodingKeys.additionalValues)

if let type = try container.decodeIfPresent(String.self, forKey: CodingKeys.type) {
self.type = type
}

}

// [Regular Expression Capture Groups in Swift](https://www.advancedswift.com/regex-capture-groups/)
public static func matchRef( in value: String ) throws -> String? {

let ref_exp = try NSRegularExpression(pattern: #"^#ref\(\s*(?<ref>[\w\d ]+[\w\d]+)\s*\)"#, options: [] )

let range = NSRange(value.startIndex..<value.endIndex, in: value)

if let match = ref_exp.firstMatch( in: value, range: range ), let range_in_string = Range( match.range( withName: "ref" ), in: value ) {
return String( value[range_in_string] )
}

return nil

}
}


struct PlantUMLSymbolGroup : Decodable, Identifiable {

var id:String {
name
}
public struct PlantUMLSymbolGroup : Decodable, Identifiable {

public var id:String { name }
var name: String
var rows: [[ Symbol ]]

func first( where predicate: ( Symbol ) -> Bool ) -> Symbol? {

for row in rows.indices {

if let result = rows[row].first(where: predicate ) {
return result
}
}

return nil
}
}




//// MARK: EQUATABLE COMPLIANCE
//extension Symbol {
//
// public static func ==(lhs: Symbol, rhs: Symbol) -> Bool {
// return lhs.id == rhs.id
// }
//}
//
//// MARK: HASHABLE COMPLIANCE
//extension Symbol {
// public func hash(into hasher: inout Hasher) {
// hasher.combine(id)
// }
//}
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
[

{
"name": "references",
"rows": [
[
{ "id": "note left", "value": "note left /' of p1 '/", "additional": ["this note is displayed left", "end note"]},
{ "id": "note right", "value": "note right /' of p1 '/", "additional": ["this note is displayed right", "end note"]},
{ "id": "note over", "value": "note over p1 /', p2 '/", "additional": ["this note is displayed over participant1", "end note"]}
]
]
},
{
"name": "general",
"rows": [
Expand Down Expand Up @@ -77,10 +87,11 @@
{ "id": "group", "value": "group My own label", "additional": ["end"] },
{ "id": "loop", "value": "loop N times", "additional": ["end"] },
{ "id": "alt", "value": "alt successful case", "additional": [ "else some kind of failure", "end"] },
{ "id": "note left", "value": "note left /' of p1 '/", "additional": ["this note is displayed left", "end note"]},
{ "id": "note right", "value": "note right /' of p1 '/", "additional": ["this note is displayed right", "end note"]},
{ "id": "note over", "value": "note over p1 /', p2 '/", "additional": ["this note is displayed over participant1", "end note"]}

{ "id": "note", "value": "note %@", "type": "choice", "additional": [
"#ref(note left)",
"#ref(note right)",
"#ref(note over)"
]}
]
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,44 @@ final class PlantUMLKeyboardTests: XCTestCase {

XCTAssertEqual( symbols[0][11].value, "queue as q1" )

print( symbols )
// print( symbols )

}


func testRef() throws {

do {

let ref_1 = try Symbol.matchRef( in: "test" )
XCTAssertNil(ref_1)

let ref_2 = try Symbol.matchRef( in: "#ref(note left)" )
XCTAssertNotNil(ref_2)
XCTAssertEqual( ref_2 , "note left" )

let ref_3 = try Symbol.matchRef( in: "#ref( note left)" )
XCTAssertNotNil(ref_3)
XCTAssertEqual( ref_3 , "note left" )

let ref_4 = try Symbol.matchRef( in: "#ref(note left )" )
XCTAssertNotNil(ref_4)
XCTAssertEqual( ref_4 , "note left" )

let ref_5 = try Symbol.matchRef( in: "#ref( note left )" )
XCTAssertNotNil(ref_5)
XCTAssertEqual( ref_5 , "note left" )

let ref_6 = try Symbol.matchRef( in: "#ref( mixed by erry )" )
XCTAssertNotNil(ref_6)
XCTAssertEqual( ref_6 , "mixed by erry" )

} catch {
XCTFail( "error evaluating isReference regular expression: \(error)")
}


// print( symbols )

}
}

0 comments on commit f74a6dc

Please sign in to comment.