├── assets
├── AppIcon.png
├── AppIcon128.png
├── AppIcon256.png
├── AppIcon64.png
├── AppIcon@2x.png
└── screenshot.png
├── Sources
└── Pretty JSON
│ └── Pretty_JSON.swift
├── Fonts
├── IBMPlexMono-Regular.otf
└── IBM-PLEX-LICENSE.md
├── Package.resolved
├── Tests
├── LinuxMain.swift
└── Pretty JSONTests
│ └── Pretty_JSONTests.swift
├── Pretty JSON
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ ├── AppIcon.png
│ │ ├── AppIcon-1.png
│ │ ├── AppIcon128.png
│ │ ├── AppIcon256.png
│ │ ├── AppIcon64.png
│ │ ├── AppIcon@2x.png
│ │ ├── AppIcon256-1.png
│ │ └── Contents.json
├── Pretty_JSON.entitlements
├── Info.plist
├── Parser.swift
├── Application.swift
├── ScrollingTextView.swift
├── MainViewController.swift
├── AppDelegate.swift
└── MainView.swift
├── Pretty JSON.xcworkspace
├── xcuserdata
│ └── andrewcrookston.xcuserdatad
│ │ └── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── Pretty JSON.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcuserdata
│ └── andrewcrookston.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
├── Package.swift
├── LICENSE
├── README.md
├── .gitignore
└── LICENSE.md
/assets/AppIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrookston/pjs/HEAD/assets/AppIcon.png
--------------------------------------------------------------------------------
/assets/AppIcon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrookston/pjs/HEAD/assets/AppIcon128.png
--------------------------------------------------------------------------------
/assets/AppIcon256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrookston/pjs/HEAD/assets/AppIcon256.png
--------------------------------------------------------------------------------
/assets/AppIcon64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrookston/pjs/HEAD/assets/AppIcon64.png
--------------------------------------------------------------------------------
/assets/AppIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrookston/pjs/HEAD/assets/AppIcon@2x.png
--------------------------------------------------------------------------------
/assets/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrookston/pjs/HEAD/assets/screenshot.png
--------------------------------------------------------------------------------
/Sources/Pretty JSON/Pretty_JSON.swift:
--------------------------------------------------------------------------------
1 | struct Pretty_JSON {
2 | var text = "Hello, World!"
3 | }
4 |
--------------------------------------------------------------------------------
/Fonts/IBMPlexMono-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrookston/pjs/HEAD/Fonts/IBMPlexMono-Regular.otf
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 |
5 | ]
6 | },
7 | "version": 1
8 | }
9 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import Pretty_JSONTests
3 |
4 | XCTMain([
5 | testCase(Pretty_JSONTests.allTests),
6 | ])
7 |
--------------------------------------------------------------------------------
/Pretty JSON/Assets.xcassets/AppIcon.appiconset/AppIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrookston/pjs/HEAD/Pretty JSON/Assets.xcassets/AppIcon.appiconset/AppIcon.png
--------------------------------------------------------------------------------
/Pretty JSON/Assets.xcassets/AppIcon.appiconset/AppIcon-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrookston/pjs/HEAD/Pretty JSON/Assets.xcassets/AppIcon.appiconset/AppIcon-1.png
--------------------------------------------------------------------------------
/Pretty JSON/Assets.xcassets/AppIcon.appiconset/AppIcon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrookston/pjs/HEAD/Pretty JSON/Assets.xcassets/AppIcon.appiconset/AppIcon128.png
--------------------------------------------------------------------------------
/Pretty JSON/Assets.xcassets/AppIcon.appiconset/AppIcon256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrookston/pjs/HEAD/Pretty JSON/Assets.xcassets/AppIcon.appiconset/AppIcon256.png
--------------------------------------------------------------------------------
/Pretty JSON/Assets.xcassets/AppIcon.appiconset/AppIcon64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrookston/pjs/HEAD/Pretty JSON/Assets.xcassets/AppIcon.appiconset/AppIcon64.png
--------------------------------------------------------------------------------
/Pretty JSON/Assets.xcassets/AppIcon.appiconset/AppIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrookston/pjs/HEAD/Pretty JSON/Assets.xcassets/AppIcon.appiconset/AppIcon@2x.png
--------------------------------------------------------------------------------
/Pretty JSON/Assets.xcassets/AppIcon.appiconset/AppIcon256-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrookston/pjs/HEAD/Pretty JSON/Assets.xcassets/AppIcon.appiconset/AppIcon256-1.png
--------------------------------------------------------------------------------
/Pretty JSON.xcworkspace/xcuserdata/andrewcrookston.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/Pretty JSON.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Pretty JSON.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Pretty JSON.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:4.0
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "Pretty JSON",
6 | dependencies: [ ],
7 | targets: [
8 | .target(
9 | name: "Pretty JSON",
10 | dependencies: []),
11 | .testTarget(
12 | name: "Pretty JSONTests",
13 | dependencies: []),
14 | ]
15 | )
16 |
--------------------------------------------------------------------------------
/Pretty JSON/Pretty_JSON.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Pretty JSON.xcodeproj/xcuserdata/andrewcrookston.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Pretty JSON.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Tests/Pretty JSONTests/Pretty_JSONTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import Pretty_JSON
3 |
4 | class Pretty_JSONTests: XCTestCase {
5 | func testExample() {
6 | // This is an example of a functional test case.
7 | // Use XCTAssert and related functions to verify your tests produce the correct
8 | // results.
9 | XCTAssertEqual(Pretty_JSON().text, "Hello, World!")
10 | }
11 |
12 |
13 | static var allTests = [
14 | ("testExample", testExample),
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Andrew Crookston
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Pretty JSON/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ATSApplicationFontsPath
6 | Fonts
7 | CFBundleDevelopmentRegion
8 | $(DEVELOPMENT_LANGUAGE)
9 | CFBundleExecutable
10 | PJs
11 | CFBundleIconFile
12 |
13 | CFBundleIdentifier
14 | $(PRODUCT_BUNDLE_IDENTIFIER)
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | PJs
19 | CFBundlePackageType
20 | APPL
21 | CFBundleShortVersionString
22 | 1.0.0
23 | CFBundleVersion
24 | 1
25 | LSMinimumSystemVersion
26 | $(MACOSX_DEPLOYMENT_TARGET)
27 | NSHumanReadableCopyright
28 | Copyright © 2017 Andrew Crookston. All rights reserved.
29 | NSPrincipalClass
30 | PJs.Application
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Pretty JSON/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "size" : "16x16",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "size" : "16x16",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "size" : "32x32",
16 | "scale" : "1x"
17 | },
18 | {
19 | "size" : "32x32",
20 | "idiom" : "mac",
21 | "filename" : "AppIcon64.png",
22 | "scale" : "2x"
23 | },
24 | {
25 | "size" : "128x128",
26 | "idiom" : "mac",
27 | "filename" : "AppIcon128.png",
28 | "scale" : "1x"
29 | },
30 | {
31 | "size" : "128x128",
32 | "idiom" : "mac",
33 | "filename" : "AppIcon256.png",
34 | "scale" : "2x"
35 | },
36 | {
37 | "size" : "256x256",
38 | "idiom" : "mac",
39 | "filename" : "AppIcon256-1.png",
40 | "scale" : "1x"
41 | },
42 | {
43 | "size" : "256x256",
44 | "idiom" : "mac",
45 | "filename" : "AppIcon-1.png",
46 | "scale" : "2x"
47 | },
48 | {
49 | "size" : "512x512",
50 | "idiom" : "mac",
51 | "filename" : "AppIcon.png",
52 | "scale" : "1x"
53 | },
54 | {
55 | "size" : "512x512",
56 | "idiom" : "mac",
57 | "filename" : "AppIcon@2x.png",
58 | "scale" : "2x"
59 | }
60 | ],
61 | "info" : {
62 | "version" : 1,
63 | "author" : "xcode"
64 | }
65 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #  PJs - Pretty JSON
2 |
3 | A simple, privacy minded macOS JSON formatter application. Making it easy to convert between minified and prettified JSON.
4 |
5 | Simply put your JSON into the Input box and select your output option.
6 |
7 | 
8 |
9 | ## Installation
10 |
11 | ### Current Version: 1.0.0
12 |
13 | Download the latest release from [Releases](https://github.com/acrookston/pjs/releases).
14 |
15 | Be aware that there is currently no automatic updating so please check back for updates.
16 |
17 | ## Contributing
18 |
19 | This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
20 |
21 | Bug reports and pull requests are welcome via GitHub at https://github.com/acrookston/pjs/issues.
22 |
23 | If you're making a big change, please open an Issue first, so we can discuss. Otherwise:
24 |
25 | - Fork the repo
26 | - Make your changes and add tests (if possible).
27 | - Create a pull-request on Github.
28 |
29 | ## Author
30 |
31 | Andrew Crookston [@acr](https://twitter.com/acr)
32 |
33 | Tweet me if you like this library, have questions or feedback.
34 |
35 | ## Releases
36 |
37 | All releases are coordinated and signed by CA Systems, owned by Andrew Crookston.
38 |
39 | ## Licenses
40 |
41 | The application source code is released under MIT License.
42 |
43 | The application includes a font by IBM. See [LICENSE](LICENSE.md) for details.
44 |
45 |
--------------------------------------------------------------------------------
/Pretty JSON/Parser.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Parser.swift
3 | // Pretty JSON
4 | //
5 | // Created by Andrew Crookston on 10/4/17.
6 | // Copyright © 2017 Andrew Crookston. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | //import Jay
11 |
12 | enum ParserErrors: Error {
13 | case parsingError(Error)
14 | case emptyString
15 | case stringEncoding
16 | }
17 |
18 | enum ParserMode {
19 | case prettified, minified
20 | }
21 |
22 | enum ParserResult {
23 | case success(T)
24 | case error(ParserErrors)
25 | }
26 |
27 | final class Parser {
28 | func parse(_ text: String, mode: ParserMode, _ callback: @escaping (ParserResult) -> ()) {
29 | if text.isEmpty {
30 | callback(.error(.emptyString))
31 | return
32 | }
33 |
34 | do {
35 | if let data = text.data(using: text.fastestEncoding) {
36 | let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions())
37 | let jsonData: Data
38 | switch mode {
39 | case .minified:
40 | jsonData = try JSONSerialization.data(withJSONObject: json, options: [])
41 | case .prettified:
42 | jsonData = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
43 | }
44 | if let string = String(data: jsonData, encoding: .utf8) {
45 | callback(.success(string))
46 | } else {
47 | callback(.error(.stringEncoding))
48 | }
49 | }
50 | } catch {
51 | print("Parsing error: \(error)")
52 | callback(.error(.parsingError(error)))
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | .build/
41 |
42 | # CocoaPods
43 | #
44 | # We recommend against adding the Pods directory to your .gitignore. However
45 | # you should judge for yourself, the pros and cons are mentioned at:
46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
47 | #
48 | # Pods/
49 |
50 | # Carthage
51 | #
52 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
53 | # Carthage/Checkouts
54 |
55 | Carthage/Build
56 |
57 | # fastlane
58 | #
59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
60 | # screenshots whenever they are needed.
61 | # For more information about the recommended setup visit:
62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
63 |
64 | fastlane/report.xml
65 | fastlane/Preview.html
66 | fastlane/screenshots
67 | fastlane/test_output
68 | .DS_Store
69 | /.build
70 | /Packages
71 | /*.xcodeproj
72 |
--------------------------------------------------------------------------------
/Pretty JSON/Application.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Application.swift
3 | // Pretty JSON
4 | //
5 | // Created by Andrew Crookston on 10/4/17.
6 | // Copyright © 2017 Andrew Crookston. All rights reserved.
7 | //
8 |
9 | import AppKit
10 |
11 | @objc final class Application: NSApplication {
12 | private let realDelegate = AppDelegate()
13 |
14 | override func run() {
15 | let app = NSApplication.shared
16 | app.delegate = realDelegate
17 | app.registerServicesMenuSendTypes([NSPasteboard.PasteboardType.string], returnTypes: [NSPasteboard.PasteboardType.string])
18 | NSApp.setActivationPolicy(.regular)
19 | NSApp.activate(ignoringOtherApps: true)
20 | super.run()
21 | }
22 |
23 | override func sendEvent(_ event: NSEvent) {
24 | if event.type == .keyDown {
25 | if (event.modifierFlags.rawValue & NSEvent.ModifierFlags.deviceIndependentFlagsMask.rawValue == NSEvent.ModifierFlags.command.rawValue) {
26 | guard let key = event.charactersIgnoringModifiers else { return }
27 | switch key.lowercased() {
28 | case "x":
29 | if NSApp.sendAction(#selector(NSText.cut(_:)), to:nil, from:self) { return }
30 | case "c":
31 | if NSApp.sendAction(#selector(NSText.copy(_:)), to:nil, from:self) { return }
32 | case "v":
33 | if NSApp.sendAction(#selector(NSText.paste(_:)), to:nil, from:self) { return }
34 | // case "z":
35 | // if NSApp.sendAction(#selector(UndoManager.undo), to:nil, from:self) { return }
36 | case "a":
37 | if NSApp.sendAction(#selector(NSText.selectAll(_:)), to:nil, from:self) { return }
38 | default:
39 | break
40 | }
41 | } else if (event.modifierFlags.rawValue & NSEvent.ModifierFlags.deviceIndependentFlagsMask.rawValue == (NSEvent.ModifierFlags.command.rawValue | NSEvent.ModifierFlags.shift.rawValue)) {
42 | if event.charactersIgnoringModifiers == "Z" {
43 | // if NSApp.sendAction(#selector(UndoManager.redo), to:nil, from:self) { return }
44 | }
45 | }
46 | }
47 | return super.sendEvent(event)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Pretty JSON/ScrollingTextView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScrollingTextView.swift
3 | // PJs
4 | //
5 | // Created by Andrew C on 6/16/18.
6 | // Copyright © 2018 Andrew Crookston. All rights reserved.
7 | //
8 |
9 | import AppKit
10 |
11 | final class ScrollTextView: NSScrollView {
12 | override init(frame frameRect: NSRect) {
13 | super.init(frame: frameRect)
14 | configure()
15 | }
16 |
17 | required init?(coder decoder: NSCoder) {
18 | super.init(coder: decoder)
19 | configure()
20 | }
21 |
22 | let textView = PlainTextView(frame: .zero)
23 |
24 | private func configure() {
25 | hasVerticalScroller = true
26 | textView.font = bestFont()
27 | textView.minSize = NSSize(width: CGFloat(0.0), height: contentSize.height)
28 | textView.maxSize = NSSize(width: Double.greatestFiniteMagnitude, height: Double.greatestFiniteMagnitude)
29 | textView.isVerticallyResizable = true
30 | textView.autoresizingMask = [.width]
31 | textView.textContainer?.widthTracksTextView = true
32 | textView.textContainer?.containerSize = NSSize(width: contentSize.width, height: CGFloat(Float.greatestFiniteMagnitude))
33 | textView.disableAutomaticBehavior()
34 | documentView = textView
35 | }
36 |
37 | private func bestFont() -> NSFont {
38 | if let font = NSFont(name: "IBMPlexMono", size: NSFont.systemFontSize) { return font }
39 | if let font = NSFont(name: "AndaleMono", size: NSFont.systemFontSize) { return font }
40 | if let font = NSFont(name: "PTMono-Regular", size: NSFont.systemFontSize) { return font }
41 | return NSFont.monospacedDigitSystemFont(ofSize: NSFont.systemFontSize, weight: .regular)
42 | }
43 | }
44 |
45 | final class PlainTextView: NSTextView {
46 | override func paste(_ sender: Any?) {
47 | pasteAsPlainText(sender)
48 | }
49 | }
50 |
51 | extension NSTextView {
52 | func disableAutomaticBehavior() {
53 | isContinuousSpellCheckingEnabled = false
54 | isAutomaticTextReplacementEnabled = false
55 | isAutomaticDataDetectionEnabled = false
56 | isAutomaticQuoteSubstitutionEnabled = false
57 | isAutomaticDashSubstitutionEnabled = false
58 | isAutomaticLinkDetectionEnabled = false
59 | if #available(OSX 10.12.2, *) {
60 | isAutomaticTextCompletionEnabled = false
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Pretty JSON/MainViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainViewController.swift
3 | // Pretty JSON
4 | //
5 | // Created by Andrew Crookston on 10/4/17.
6 | // Copyright © 2017 Andrew Crookston. All rights reserved.
7 | //
8 |
9 | import AppKit
10 |
11 | protocol ParserInputDelegate: class {
12 | func parseText(input: String, mode: ParserMode)
13 | func copyOutput()
14 | }
15 |
16 | final class MainViewController: NSViewController {
17 | required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
18 | init(sender: Any?) { super.init(nibName: nil, bundle: nil) }
19 |
20 | // MARK: - View loading
21 |
22 | private lazy var mainView = MainView(delegate: self)
23 |
24 | override func loadView() {
25 | // Prevents loading from nib
26 | view = mainView
27 | }
28 |
29 | override func viewDidAppear() {
30 | let screen = NSScreen.main?.frame.size ?? .zero
31 | let origin = CGPoint(x: (screen.width - NSWindow.desiredSize.width) / 2, y: (screen.height - NSWindow.desiredSize.height) / 2)
32 | self.view.window?.setFrame(NSRect(origin: origin, size: NSWindow.desiredSize), display: true)
33 |
34 | mainView.inputView.becomeFirstResponder()
35 | }
36 |
37 | // MARK: - NotificationCenter
38 |
39 | @objc func textPaste() {
40 | if let text = NSPasteboard.general.string(forType: .string) {
41 | mainView.inputView.textView.string = text
42 | parseInputText()
43 | }
44 | }
45 |
46 | // MARK: - actions
47 |
48 | private func parseInputText() {
49 | parseText(input: mainView.inputView.textView.string, mode: mainView.parsingMode)
50 | }
51 | }
52 |
53 | extension MainViewController: ParserInputDelegate {
54 | func parseText(input: String, mode: ParserMode) {
55 | Parser().parse(input, mode: mode) { [weak self] result in
56 | switch result {
57 | case .success(let parsedString):
58 | self?.mainView.outputView.textView.string = parsedString
59 | case .error(let error):
60 | switch error {
61 | case ParserErrors.emptyString:
62 | self?.mainView.outputView.textView.string = ""
63 | default:
64 | self?.mainView.outputView.textView.string = "PARSING ERROR:\n\n\(error.localizedDescription)"
65 | }
66 | }
67 | }
68 | }
69 |
70 | func copyOutput() {
71 | NSPasteboard.general.declareTypes([.string], owner: nil)
72 | NSPasteboard.general.setString(mainView.outputView.textView.string, forType: .string)
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Pretty JSON/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Pretty JSON
4 | //
5 | // Created by Andrew Crookston on 10/4/17.
6 | // Copyright © 2017 Andrew Crookston. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Cocoa
11 |
12 | extension NSWindow {
13 | static let desiredSize: CGSize = CGSize(width: 800, height: 600)
14 | }
15 |
16 | @NSApplicationMain
17 | final class AppDelegate: NSObject, NSApplicationDelegate {
18 | var windowController: NSWindowController?
19 | var window: NSWindow?
20 |
21 | func applicationDidFinishLaunching(_ aNotification: Notification) {
22 | NSApp.mainMenu = mainMenu
23 | window = NSWindow(contentRect: .zero,
24 | styleMask: [.titled, .closable, .resizable, .miniaturizable],
25 | backing: .buffered,
26 | defer: false)
27 | window?.title = "PJs"
28 | windowController = NSWindowController(window: window)
29 | window?.contentViewController = MainViewController(sender: nil)
30 | window?.makeKeyAndOrderFront(nil)
31 | windowController?.showWindow(nil)
32 | }
33 |
34 | func applicationWillTerminate(_ aNotification: Notification) {
35 | // Insert code here to tear down your application
36 | }
37 |
38 | private lazy var mainMenu: NSMenu = {
39 | let mainMenu = NSMenu()
40 | let appMenuItem = NSMenuItem(title: "PJs", action: nil, keyEquivalent: "")
41 | let appMenu = NSMenu(title: "PJs")
42 | appMenu.addItem(withTitle: "Quit", action: #selector(terminateApplication), keyEquivalent: "q")
43 | appMenuItem.submenu = appMenu
44 |
45 | let editMenuItem = NSMenuItem(title: "Edit", action: nil, keyEquivalent: "f")
46 | let editMenu = NSMenu(title: "Edit")
47 | editMenu.addItem(withTitle: "Copy", action: #selector(textCopy), keyEquivalent: "c")
48 | editMenu.addItem(withTitle: "Paste", action: #selector(textPaste), keyEquivalent: "v")
49 | editMenu.addItem(withTitle: "Cut", action: #selector(textCut), keyEquivalent: "x")
50 | editMenu.addItem(withTitle: "Select All", action: #selector(textSelectAll), keyEquivalent: "a")
51 | editMenuItem.submenu = editMenu
52 |
53 | mainMenu.addItem(appMenuItem)
54 | mainMenu.addItem(editMenuItem)
55 |
56 | return mainMenu
57 | }()
58 |
59 | // MARK: - Menu callbacks
60 |
61 | @objc func terminateApplication() {
62 | NSApp.terminate(nil)
63 | }
64 |
65 | @objc private func textPaste() {
66 | NSApp.sendAction(#selector(NSText.paste(_:)), to:nil, from:self)
67 | }
68 |
69 | @objc private func textCut() {
70 | NSApp.sendAction(#selector(NSText.cut(_:)), to:nil, from:self)
71 | }
72 |
73 | @objc private func textCopy() {
74 | NSApp.sendAction(#selector(NSText.copy(_:)), to:nil, from:self)
75 | }
76 |
77 | @objc private func textSelectAll() {
78 | NSApp.sendAction(#selector(NSText.selectAll(_:)), to:nil, from:self)
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Fonts/IBM-PLEX-LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright © 2017 IBM Corp. with Reserved Font Name "Plex"
2 |
3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
4 |
5 | This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
6 |
7 |
8 | -----------------------------------------------------------
9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10 | -----------------------------------------------------------
11 |
12 | PREAMBLE
13 | The goals of the Open Font License (OFL) are to stimulate worldwide
14 | development of collaborative font projects, to support the font creation
15 | efforts of academic and linguistic communities, and to provide a free and
16 | open framework in which fonts may be shared and improved in partnership
17 | with others.
18 |
19 | The OFL allows the licensed fonts to be used, studied, modified and
20 | redistributed freely as long as they are not sold by themselves. The
21 | fonts, including any derivative works, can be bundled, embedded,
22 | redistributed and/or sold with any software provided that any reserved
23 | names are not used by derivative works. The fonts and derivatives,
24 | however, cannot be released under any other type of license. The
25 | requirement for fonts to remain under this license does not apply
26 | to any document created using the fonts or their derivatives.
27 |
28 | DEFINITIONS
29 | "Font Software" refers to the set of files released by the Copyright
30 | Holder(s) under this license and clearly marked as such. This may
31 | include source files, build scripts and documentation.
32 |
33 | "Reserved Font Name" refers to any names specified as such after the
34 | copyright statement(s).
35 |
36 | "Original Version" refers to the collection of Font Software components as
37 | distributed by the Copyright Holder(s).
38 |
39 | "Modified Version" refers to any derivative made by adding to, deleting,
40 | or substituting -- in part or in whole -- any of the components of the
41 | Original Version, by changing formats or by porting the Font Software to a
42 | new environment.
43 |
44 | "Author" refers to any designer, engineer, programmer, technical
45 | writer or other person who contributed to the Font Software.
46 |
47 | PERMISSION & CONDITIONS
48 | Permission is hereby granted, free of charge, to any person obtaining
49 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
50 | redistribute, and sell modified and unmodified copies of the Font
51 | Software, subject to the following conditions:
52 |
53 | 1) Neither the Font Software nor any of its individual components,
54 | in Original or Modified Versions, may be sold by itself.
55 |
56 | 2) Original or Modified Versions of the Font Software may be bundled,
57 | redistributed and/or sold with any software, provided that each copy
58 | contains the above copyright notice and this license. These can be
59 | included either as stand-alone text files, human-readable headers or
60 | in the appropriate machine-readable metadata fields within text or
61 | binary files as long as those fields can be easily viewed by the user.
62 |
63 | 3) No Modified Version of the Font Software may use the Reserved Font
64 | Name(s) unless explicit written permission is granted by the corresponding
65 | Copyright Holder. This restriction only applies to the primary font name as
66 | presented to the users.
67 |
68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69 | Software shall not be used to promote, endorse or advertise any
70 | Modified Version, except to acknowledge the contribution(s) of the
71 | Copyright Holder(s) and the Author(s) or with their explicit written
72 | permission.
73 |
74 | 5) The Font Software, modified or unmodified, in part or in whole,
75 | must be distributed entirely under this license, and must not be
76 | distributed under any other license. The requirement for fonts to
77 | remain under this license does not apply to any document created
78 | using the Font Software.
79 |
80 | TERMINATION
81 | This license becomes null and void if any of the above conditions are
82 | not met.
83 |
84 | DISCLAIMER
85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93 | OTHER DEALINGS IN THE FONT SOFTWARE.
94 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # Application License
2 |
3 | The MIT License
4 |
5 | Copyright (c) 2010-2018 Andrew Crookston
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in
15 | all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | THE SOFTWARE.
24 |
25 |
26 | # Font License
27 |
28 | Copyright © 2017 IBM Corp. with Reserved Font Name "Plex"
29 |
30 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
31 |
32 | This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
33 |
34 |
35 | -----------------------------------------------------------
36 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
37 | -----------------------------------------------------------
38 |
39 | PREAMBLE
40 | The goals of the Open Font License (OFL) are to stimulate worldwide
41 | development of collaborative font projects, to support the font creation
42 | efforts of academic and linguistic communities, and to provide a free and
43 | open framework in which fonts may be shared and improved in partnership
44 | with others.
45 |
46 | The OFL allows the licensed fonts to be used, studied, modified and
47 | redistributed freely as long as they are not sold by themselves. The
48 | fonts, including any derivative works, can be bundled, embedded,
49 | redistributed and/or sold with any software provided that any reserved
50 | names are not used by derivative works. The fonts and derivatives,
51 | however, cannot be released under any other type of license. The
52 | requirement for fonts to remain under this license does not apply
53 | to any document created using the fonts or their derivatives.
54 |
55 | DEFINITIONS
56 | "Font Software" refers to the set of files released by the Copyright
57 | Holder(s) under this license and clearly marked as such. This may
58 | include source files, build scripts and documentation.
59 |
60 | "Reserved Font Name" refers to any names specified as such after the
61 | copyright statement(s).
62 |
63 | "Original Version" refers to the collection of Font Software components as
64 | distributed by the Copyright Holder(s).
65 |
66 | "Modified Version" refers to any derivative made by adding to, deleting,
67 | or substituting -- in part or in whole -- any of the components of the
68 | Original Version, by changing formats or by porting the Font Software to a
69 | new environment.
70 |
71 | "Author" refers to any designer, engineer, programmer, technical
72 | writer or other person who contributed to the Font Software.
73 |
74 | PERMISSION & CONDITIONS
75 | Permission is hereby granted, free of charge, to any person obtaining
76 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
77 | redistribute, and sell modified and unmodified copies of the Font
78 | Software, subject to the following conditions:
79 |
80 | 1) Neither the Font Software nor any of its individual components,
81 | in Original or Modified Versions, may be sold by itself.
82 |
83 | 2) Original or Modified Versions of the Font Software may be bundled,
84 | redistributed and/or sold with any software, provided that each copy
85 | contains the above copyright notice and this license. These can be
86 | included either as stand-alone text files, human-readable headers or
87 | in the appropriate machine-readable metadata fields within text or
88 | binary files as long as those fields can be easily viewed by the user.
89 |
90 | 3) No Modified Version of the Font Software may use the Reserved Font
91 | Name(s) unless explicit written permission is granted by the corresponding
92 | Copyright Holder. This restriction only applies to the primary font name as
93 | presented to the users.
94 |
95 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
96 | Software shall not be used to promote, endorse or advertise any
97 | Modified Version, except to acknowledge the contribution(s) of the
98 | Copyright Holder(s) and the Author(s) or with their explicit written
99 | permission.
100 |
101 | 5) The Font Software, modified or unmodified, in part or in whole,
102 | must be distributed entirely under this license, and must not be
103 | distributed under any other license. The requirement for fonts to
104 | remain under this license does not apply to any document created
105 | using the Font Software.
106 |
107 | TERMINATION
108 | This license becomes null and void if any of the above conditions are
109 | not met.
110 |
111 | DISCLAIMER
112 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
113 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
114 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
115 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
116 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
117 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
118 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
119 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
120 | OTHER DEALINGS IN THE FONT SOFTWARE.
121 |
--------------------------------------------------------------------------------
/Pretty JSON/MainView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainView.swift
3 | // PJs
4 | //
5 | // Created by Andrew C on 6/17/18.
6 | // Copyright © 2018 Andrew Crookston. All rights reserved.
7 | //
8 |
9 | import AppKit
10 |
11 | // NOTE: Consider using NSSplitView (for resizing?)
12 |
13 | final class MainView: NSView {
14 | required init?(coder decoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
15 |
16 | init(delegate: ParserInputDelegate) {
17 | super.init(frame: .zero)
18 | self.delegate = delegate
19 | inputBackground.addSubview(inputView)
20 | outputBackground.addSubview(outputView)
21 | inputView.textView.delegate = self
22 | addSubview(ouputSegmentControl)
23 | addSubview(inputTitle)
24 | addSubview(outputTitle)
25 | addSubview(inputBackground)
26 | addSubview(outputBackground)
27 | addSubview(copyButton)
28 | setupConstraints()
29 | }
30 |
31 | // MARK: - Public properties
32 |
33 | weak var delegate: ParserInputDelegate?
34 | var parsingMode: ParserMode = .prettified {
35 | didSet {
36 | delegate?.parseText(input: inputView.textView.string, mode: parsingMode)
37 | }
38 | }
39 |
40 | // MARK: - View setup
41 |
42 | private func setupConstraints() {
43 | inputBackground.translatesAutoresizingMaskIntoConstraints = false
44 | outputBackground.translatesAutoresizingMaskIntoConstraints = false
45 | inputView.translatesAutoresizingMaskIntoConstraints = false
46 | outputView.translatesAutoresizingMaskIntoConstraints = false
47 | inputTitle.translatesAutoresizingMaskIntoConstraints = false
48 | outputTitle.translatesAutoresizingMaskIntoConstraints = false
49 | ouputSegmentControl.translatesAutoresizingMaskIntoConstraints = false
50 | copyButton.translatesAutoresizingMaskIntoConstraints = false
51 |
52 | let spacing: CGFloat = 10
53 | let padding: CGFloat = 5
54 | NSLayoutConstraint.activate([
55 | ouputSegmentControl.topAnchor.constraint(equalTo: self.topAnchor, constant: spacing),
56 | ouputSegmentControl.centerXAnchor.constraint(equalTo: self.centerXAnchor),
57 |
58 | inputTitle.topAnchor.constraint(equalTo: ouputSegmentControl.bottomAnchor, constant: spacing),
59 | inputTitle.leftAnchor.constraint(equalTo: self.leftAnchor, constant: spacing),
60 | inputTitle.rightAnchor.constraint(equalTo: self.centerXAnchor, constant: -padding),
61 |
62 | outputTitle.topAnchor.constraint(equalTo: ouputSegmentControl.bottomAnchor, constant: spacing),
63 | outputTitle.leftAnchor.constraint(equalTo: self.centerXAnchor, constant: padding),
64 | outputTitle.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.25, constant: 0),
65 |
66 | copyButton.centerYAnchor.constraint(equalTo: outputTitle.centerYAnchor),
67 | copyButton.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -spacing),
68 |
69 | inputBackground.topAnchor.constraint(equalTo: inputTitle.bottomAnchor, constant: spacing),
70 | inputBackground.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -spacing),
71 | inputBackground.leftAnchor.constraint(equalTo: self.leftAnchor, constant: spacing),
72 | inputBackground.rightAnchor.constraint(equalTo: self.centerXAnchor, constant: -padding),
73 |
74 | inputView.topAnchor.constraint(equalTo: inputBackground.topAnchor, constant: padding),
75 | inputView.bottomAnchor.constraint(equalTo: inputBackground.bottomAnchor, constant: -padding),
76 | inputView.leftAnchor.constraint(equalTo: inputBackground.leftAnchor, constant: padding),
77 | inputView.rightAnchor.constraint(equalTo: inputBackground.rightAnchor, constant: -padding),
78 |
79 | outputBackground.topAnchor.constraint(equalTo: outputTitle.bottomAnchor, constant: spacing),
80 | outputBackground.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -spacing),
81 | outputBackground.leftAnchor.constraint(equalTo: self.centerXAnchor, constant: padding),
82 | outputBackground.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -spacing),
83 |
84 | outputView.topAnchor.constraint(equalTo: outputBackground.topAnchor, constant: padding),
85 | outputView.bottomAnchor.constraint(equalTo: outputBackground.bottomAnchor, constant: -padding),
86 | outputView.leftAnchor.constraint(equalTo: outputBackground.leftAnchor, constant: padding),
87 | outputView.rightAnchor.constraint(equalTo: outputBackground.rightAnchor, constant: -padding)
88 | ])
89 | }
90 |
91 | // MARK: - actions
92 |
93 | @objc private func didTapSegment(sender: NSSegmentedControl) {
94 | switch sender.indexOfSelectedItem {
95 | case 0:
96 | parsingMode = .prettified
97 | default:
98 | parsingMode = .minified
99 | }
100 | }
101 |
102 | @objc private func didTapCopy(sender: NSButton) {
103 | delegate?.copyOutput()
104 | }
105 |
106 | // MARK: - child view
107 |
108 | private let inputTitle: NSTextField = {
109 | let view = NSTextField(frame: .zero)
110 | view.isBezeled = false
111 | view.isEditable = false
112 | view.isSelectable = false
113 | view.drawsBackground = false
114 | view.font = .boldSystemFont(ofSize: NSFont.systemFontSize)
115 | view.stringValue = NSLocalizedString("Input", comment: "input title")
116 | return view
117 | }()
118 |
119 | private let outputTitle: NSTextField = {
120 | let view = NSTextField(frame: .zero)
121 | view.isBezeled = false
122 | view.isEditable = false
123 | view.isSelectable = false
124 | view.drawsBackground = false
125 | view.font = .boldSystemFont(ofSize: NSFont.systemFontSize)
126 | view.stringValue = NSLocalizedString("Output", comment: "output title")
127 | return view
128 | }()
129 |
130 | private let ouputSegmentControl: NSSegmentedControl = {
131 | let strings = [
132 | NSLocalizedString("Prettified", comment: "prettified segment control"),
133 | NSLocalizedString("Minimized", comment: "minimized segment control")
134 | ]
135 | let segment = NSSegmentedControl(labels: strings,
136 | trackingMode: .selectOne,
137 | target: self,
138 | action: #selector(didTapSegment))
139 | segment.selectedSegment = 0
140 | return segment
141 | }()
142 |
143 | private let inputBackground: NSView = {
144 | let view = NSView(frame: .zero)
145 | view.wantsLayer = true
146 | view.layer?.borderColor = NSColor.lightGray.cgColor
147 | view.layer?.borderWidth = 1
148 | view.layer?.backgroundColor = NSColor.white.cgColor
149 | return view
150 | }()
151 |
152 | private let outputBackground: NSView = {
153 | let view = NSView(frame: .zero)
154 | view.wantsLayer = true
155 | view.layer?.borderColor = NSColor.lightGray.cgColor
156 | view.layer?.borderWidth = 1
157 | view.layer?.backgroundColor = NSColor(calibratedRed: 224/255, green: 224/255, blue: 224/255, alpha: 1).cgColor
158 | return view
159 | }()
160 |
161 | private lazy var copyButton: NSButton = NSButton(title: NSLocalizedString("Copy output", comment: "copy button"),
162 | target: self,
163 | action: #selector(didTapCopy))
164 |
165 | let inputView: ScrollTextView = {
166 | let scrollText = ScrollTextView(frame: .zero)
167 | scrollText.textView.isEditable = true
168 | scrollText.textView.isSelectable = true
169 | scrollText.drawsBackground = false
170 | return scrollText
171 | }()
172 |
173 | let outputView: ScrollTextView = {
174 | let scrollText = ScrollTextView(frame: .zero)
175 | scrollText.textView.drawsBackground = false
176 | scrollText.textView.isEditable = false
177 | scrollText.textView.isSelectable = true
178 | scrollText.drawsBackground = false
179 | return scrollText
180 | }()
181 | }
182 |
183 | extension MainView: NSTextViewDelegate {
184 | func textDidChange(_ notification: Notification) {
185 | delegate?.parseText(input: inputView.textView.string, mode: parsingMode)
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/Pretty JSON.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 48;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | A1B8B4A320D5DC5F001D066C /* ScrollingTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B8B4A220D5DC5F001D066C /* ScrollingTextView.swift */; };
11 | A1B8B4A520D71C1D001D066C /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B8B4A420D71C1D001D066C /* MainView.swift */; };
12 | A1B8B4A820D7445A001D066C /* IBMPlexMono-Regular.otf in CopyFiles */ = {isa = PBXBuildFile; fileRef = C1BA9E9920D47FD9009D8ADA /* IBMPlexMono-Regular.otf */; };
13 | A1B8B4AA20D744B4001D066C /* LICENSE.md in Resources */ = {isa = PBXBuildFile; fileRef = A1B8B4A920D744B4001D066C /* LICENSE.md */; };
14 | C129DACE1F8572780007C8CE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C129DACD1F8572780007C8CE /* AppDelegate.swift */; };
15 | C129DAD01F8572780007C8CE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C129DACF1F8572780007C8CE /* Assets.xcassets */; };
16 | C129DAE11F8576E60007C8CE /* Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C129DAE01F8576E60007C8CE /* Parser.swift */; };
17 | C129DAE31F85774D0007C8CE /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C129DAE21F85774D0007C8CE /* MainViewController.swift */; };
18 | C129DAE51F85A62F0007C8CE /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = C129DAE41F85A62F0007C8CE /* Application.swift */; };
19 | /* End PBXBuildFile section */
20 |
21 | /* Begin PBXCopyFilesBuildPhase section */
22 | A1B8B4A720D7444D001D066C /* CopyFiles */ = {
23 | isa = PBXCopyFilesBuildPhase;
24 | buildActionMask = 2147483647;
25 | dstPath = Fonts;
26 | dstSubfolderSpec = 7;
27 | files = (
28 | A1B8B4A820D7445A001D066C /* IBMPlexMono-Regular.otf in CopyFiles */,
29 | );
30 | runOnlyForDeploymentPostprocessing = 0;
31 | };
32 | /* End PBXCopyFilesBuildPhase section */
33 |
34 | /* Begin PBXFileReference section */
35 | A1B8B4A220D5DC5F001D066C /* ScrollingTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollingTextView.swift; sourceTree = ""; };
36 | A1B8B4A420D71C1D001D066C /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; };
37 | A1B8B4A920D744B4001D066C /* LICENSE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = ""; };
38 | A1B8B4AB20D744FD001D066C /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
39 | C129DACA1F8572780007C8CE /* PJs.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PJs.app; sourceTree = BUILT_PRODUCTS_DIR; };
40 | C129DACD1F8572780007C8CE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
41 | C129DACF1F8572780007C8CE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
42 | C129DAD41F8572780007C8CE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
43 | C129DAD51F8572780007C8CE /* Pretty_JSON.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Pretty_JSON.entitlements; sourceTree = ""; };
44 | C129DADB1F8574E30007C8CE /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; };
45 | C129DADC1F8574E80007C8CE /* Package.resolved */ = {isa = PBXFileReference; lastKnownFileType = text; path = Package.resolved; sourceTree = ""; };
46 | C129DAE01F8576E60007C8CE /* Parser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Parser.swift; sourceTree = ""; };
47 | C129DAE21F85774D0007C8CE /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; };
48 | C129DAE41F85A62F0007C8CE /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; };
49 | C1BA9E9820D44257009D8ADA /* IBM-PLEX-LICENSE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "IBM-PLEX-LICENSE.md"; sourceTree = ""; };
50 | C1BA9E9920D47FD9009D8ADA /* IBMPlexMono-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "IBMPlexMono-Regular.otf"; sourceTree = ""; };
51 | /* End PBXFileReference section */
52 |
53 | /* Begin PBXFrameworksBuildPhase section */
54 | C129DAC71F8572780007C8CE /* Frameworks */ = {
55 | isa = PBXFrameworksBuildPhase;
56 | buildActionMask = 2147483647;
57 | files = (
58 | );
59 | runOnlyForDeploymentPostprocessing = 0;
60 | };
61 | /* End PBXFrameworksBuildPhase section */
62 |
63 | /* Begin PBXGroup section */
64 | A1B8B4A620D743C2001D066C /* Fonts */ = {
65 | isa = PBXGroup;
66 | children = (
67 | C1BA9E9820D44257009D8ADA /* IBM-PLEX-LICENSE.md */,
68 | C1BA9E9920D47FD9009D8ADA /* IBMPlexMono-Regular.otf */,
69 | );
70 | path = Fonts;
71 | sourceTree = "";
72 | };
73 | C129DAC11F8572780007C8CE = {
74 | isa = PBXGroup;
75 | children = (
76 | A1B8B4AB20D744FD001D066C /* README.md */,
77 | A1B8B4A920D744B4001D066C /* LICENSE.md */,
78 | C129DADB1F8574E30007C8CE /* Package.swift */,
79 | C129DADC1F8574E80007C8CE /* Package.resolved */,
80 | A1B8B4A620D743C2001D066C /* Fonts */,
81 | C129DACC1F8572780007C8CE /* Pretty JSON */,
82 | C129DACB1F8572780007C8CE /* Products */,
83 | C129DADD1F8576C50007C8CE /* Frameworks */,
84 | );
85 | sourceTree = "";
86 | };
87 | C129DACB1F8572780007C8CE /* Products */ = {
88 | isa = PBXGroup;
89 | children = (
90 | C129DACA1F8572780007C8CE /* PJs.app */,
91 | );
92 | name = Products;
93 | sourceTree = "";
94 | };
95 | C129DACC1F8572780007C8CE /* Pretty JSON */ = {
96 | isa = PBXGroup;
97 | children = (
98 | C129DACD1F8572780007C8CE /* AppDelegate.swift */,
99 | C129DACF1F8572780007C8CE /* Assets.xcassets */,
100 | C129DAD41F8572780007C8CE /* Info.plist */,
101 | C129DAD51F8572780007C8CE /* Pretty_JSON.entitlements */,
102 | C129DAE01F8576E60007C8CE /* Parser.swift */,
103 | C129DAE21F85774D0007C8CE /* MainViewController.swift */,
104 | C129DAE41F85A62F0007C8CE /* Application.swift */,
105 | A1B8B4A220D5DC5F001D066C /* ScrollingTextView.swift */,
106 | A1B8B4A420D71C1D001D066C /* MainView.swift */,
107 | );
108 | path = "Pretty JSON";
109 | sourceTree = "";
110 | };
111 | C129DADD1F8576C50007C8CE /* Frameworks */ = {
112 | isa = PBXGroup;
113 | children = (
114 | );
115 | name = Frameworks;
116 | sourceTree = "";
117 | };
118 | /* End PBXGroup section */
119 |
120 | /* Begin PBXNativeTarget section */
121 | C129DAC91F8572780007C8CE /* PJs */ = {
122 | isa = PBXNativeTarget;
123 | buildConfigurationList = C129DAD81F8572780007C8CE /* Build configuration list for PBXNativeTarget "PJs" */;
124 | buildPhases = (
125 | C129DAC61F8572780007C8CE /* Sources */,
126 | C129DAC71F8572780007C8CE /* Frameworks */,
127 | C129DAC81F8572780007C8CE /* Resources */,
128 | A1B8B4A720D7444D001D066C /* CopyFiles */,
129 | );
130 | buildRules = (
131 | );
132 | dependencies = (
133 | );
134 | name = PJs;
135 | productName = "Pretty JSON";
136 | productReference = C129DACA1F8572780007C8CE /* PJs.app */;
137 | productType = "com.apple.product-type.application";
138 | };
139 | /* End PBXNativeTarget section */
140 |
141 | /* Begin PBXProject section */
142 | C129DAC21F8572780007C8CE /* Project object */ = {
143 | isa = PBXProject;
144 | attributes = {
145 | LastSwiftUpdateCheck = 0900;
146 | LastUpgradeCheck = 0930;
147 | ORGANIZATIONNAME = "Andrew Crookston";
148 | TargetAttributes = {
149 | C129DAC91F8572780007C8CE = {
150 | CreatedOnToolsVersion = 9.0;
151 | ProvisioningStyle = Automatic;
152 | };
153 | };
154 | };
155 | buildConfigurationList = C129DAC51F8572780007C8CE /* Build configuration list for PBXProject "Pretty JSON" */;
156 | compatibilityVersion = "Xcode 8.0";
157 | developmentRegion = en;
158 | hasScannedForEncodings = 0;
159 | knownRegions = (
160 | en,
161 | Base,
162 | );
163 | mainGroup = C129DAC11F8572780007C8CE;
164 | productRefGroup = C129DACB1F8572780007C8CE /* Products */;
165 | projectDirPath = "";
166 | projectRoot = "";
167 | targets = (
168 | C129DAC91F8572780007C8CE /* PJs */,
169 | );
170 | };
171 | /* End PBXProject section */
172 |
173 | /* Begin PBXResourcesBuildPhase section */
174 | C129DAC81F8572780007C8CE /* Resources */ = {
175 | isa = PBXResourcesBuildPhase;
176 | buildActionMask = 2147483647;
177 | files = (
178 | A1B8B4AA20D744B4001D066C /* LICENSE.md in Resources */,
179 | C129DAD01F8572780007C8CE /* Assets.xcassets in Resources */,
180 | );
181 | runOnlyForDeploymentPostprocessing = 0;
182 | };
183 | /* End PBXResourcesBuildPhase section */
184 |
185 | /* Begin PBXSourcesBuildPhase section */
186 | C129DAC61F8572780007C8CE /* Sources */ = {
187 | isa = PBXSourcesBuildPhase;
188 | buildActionMask = 2147483647;
189 | files = (
190 | C129DAE51F85A62F0007C8CE /* Application.swift in Sources */,
191 | A1B8B4A520D71C1D001D066C /* MainView.swift in Sources */,
192 | A1B8B4A320D5DC5F001D066C /* ScrollingTextView.swift in Sources */,
193 | C129DAE31F85774D0007C8CE /* MainViewController.swift in Sources */,
194 | C129DAE11F8576E60007C8CE /* Parser.swift in Sources */,
195 | C129DACE1F8572780007C8CE /* AppDelegate.swift in Sources */,
196 | );
197 | runOnlyForDeploymentPostprocessing = 0;
198 | };
199 | /* End PBXSourcesBuildPhase section */
200 |
201 | /* Begin XCBuildConfiguration section */
202 | C129DAD61F8572780007C8CE /* Debug */ = {
203 | isa = XCBuildConfiguration;
204 | buildSettings = {
205 | ALWAYS_SEARCH_USER_PATHS = NO;
206 | CLANG_ANALYZER_NONNULL = YES;
207 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
208 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
209 | CLANG_CXX_LIBRARY = "libc++";
210 | CLANG_ENABLE_MODULES = YES;
211 | CLANG_ENABLE_OBJC_ARC = YES;
212 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
213 | CLANG_WARN_BOOL_CONVERSION = YES;
214 | CLANG_WARN_COMMA = YES;
215 | CLANG_WARN_CONSTANT_CONVERSION = YES;
216 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
217 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
218 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
219 | CLANG_WARN_EMPTY_BODY = YES;
220 | CLANG_WARN_ENUM_CONVERSION = YES;
221 | CLANG_WARN_INFINITE_RECURSION = YES;
222 | CLANG_WARN_INT_CONVERSION = YES;
223 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
224 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
225 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
226 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
227 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
228 | CLANG_WARN_STRICT_PROTOTYPES = YES;
229 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
230 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
231 | CLANG_WARN_UNREACHABLE_CODE = YES;
232 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
233 | CODE_SIGN_IDENTITY = "-";
234 | COPY_PHASE_STRIP = NO;
235 | DEBUG_INFORMATION_FORMAT = dwarf;
236 | ENABLE_STRICT_OBJC_MSGSEND = YES;
237 | ENABLE_TESTABILITY = YES;
238 | GCC_C_LANGUAGE_STANDARD = gnu11;
239 | GCC_DYNAMIC_NO_PIC = NO;
240 | GCC_NO_COMMON_BLOCKS = YES;
241 | GCC_OPTIMIZATION_LEVEL = 0;
242 | GCC_PREPROCESSOR_DEFINITIONS = (
243 | "DEBUG=1",
244 | "$(inherited)",
245 | );
246 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
247 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
248 | GCC_WARN_UNDECLARED_SELECTOR = YES;
249 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
250 | GCC_WARN_UNUSED_FUNCTION = YES;
251 | GCC_WARN_UNUSED_VARIABLE = YES;
252 | MACOSX_DEPLOYMENT_TARGET = 10.12;
253 | MTL_ENABLE_DEBUG_INFO = YES;
254 | ONLY_ACTIVE_ARCH = YES;
255 | SDKROOT = macosx;
256 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
257 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
258 | };
259 | name = Debug;
260 | };
261 | C129DAD71F8572780007C8CE /* Release */ = {
262 | isa = XCBuildConfiguration;
263 | buildSettings = {
264 | ALWAYS_SEARCH_USER_PATHS = NO;
265 | CLANG_ANALYZER_NONNULL = YES;
266 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
267 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
268 | CLANG_CXX_LIBRARY = "libc++";
269 | CLANG_ENABLE_MODULES = YES;
270 | CLANG_ENABLE_OBJC_ARC = YES;
271 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
272 | CLANG_WARN_BOOL_CONVERSION = YES;
273 | CLANG_WARN_COMMA = YES;
274 | CLANG_WARN_CONSTANT_CONVERSION = YES;
275 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
276 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
277 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
278 | CLANG_WARN_EMPTY_BODY = YES;
279 | CLANG_WARN_ENUM_CONVERSION = YES;
280 | CLANG_WARN_INFINITE_RECURSION = YES;
281 | CLANG_WARN_INT_CONVERSION = YES;
282 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
283 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
284 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
285 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
286 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
287 | CLANG_WARN_STRICT_PROTOTYPES = YES;
288 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
289 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
290 | CLANG_WARN_UNREACHABLE_CODE = YES;
291 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
292 | CODE_SIGN_IDENTITY = "-";
293 | COPY_PHASE_STRIP = NO;
294 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
295 | ENABLE_NS_ASSERTIONS = NO;
296 | ENABLE_STRICT_OBJC_MSGSEND = YES;
297 | GCC_C_LANGUAGE_STANDARD = gnu11;
298 | GCC_NO_COMMON_BLOCKS = YES;
299 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
300 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
301 | GCC_WARN_UNDECLARED_SELECTOR = YES;
302 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
303 | GCC_WARN_UNUSED_FUNCTION = YES;
304 | GCC_WARN_UNUSED_VARIABLE = YES;
305 | MACOSX_DEPLOYMENT_TARGET = 10.12;
306 | MTL_ENABLE_DEBUG_INFO = NO;
307 | SDKROOT = macosx;
308 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
309 | };
310 | name = Release;
311 | };
312 | C129DAD91F8572780007C8CE /* Debug */ = {
313 | isa = XCBuildConfiguration;
314 | buildSettings = {
315 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
316 | CODE_SIGN_ENTITLEMENTS = "Pretty JSON/Pretty_JSON.entitlements";
317 | CODE_SIGN_STYLE = Automatic;
318 | COMBINE_HIDPI_IMAGES = YES;
319 | INFOPLIST_FILE = "Pretty JSON/Info.plist";
320 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
321 | PRODUCT_BUNDLE_IDENTIFIER = se.crookston.pjs;
322 | PRODUCT_NAME = "${TARGET_NAME}";
323 | SWIFT_INCLUDE_PATHS = "$(SRCROOT)/.build/debug";
324 | SWIFT_VERSION = 4.0;
325 | };
326 | name = Debug;
327 | };
328 | C129DADA1F8572780007C8CE /* Release */ = {
329 | isa = XCBuildConfiguration;
330 | buildSettings = {
331 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
332 | CODE_SIGN_ENTITLEMENTS = "Pretty JSON/Pretty_JSON.entitlements";
333 | CODE_SIGN_STYLE = Automatic;
334 | COMBINE_HIDPI_IMAGES = YES;
335 | INFOPLIST_FILE = "Pretty JSON/Info.plist";
336 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
337 | PRODUCT_BUNDLE_IDENTIFIER = se.crookston.pjs;
338 | PRODUCT_NAME = "${TARGET_NAME}";
339 | SWIFT_INCLUDE_PATHS = "$(SRCROOT)/.build/debug";
340 | SWIFT_VERSION = 4.0;
341 | };
342 | name = Release;
343 | };
344 | /* End XCBuildConfiguration section */
345 |
346 | /* Begin XCConfigurationList section */
347 | C129DAC51F8572780007C8CE /* Build configuration list for PBXProject "Pretty JSON" */ = {
348 | isa = XCConfigurationList;
349 | buildConfigurations = (
350 | C129DAD61F8572780007C8CE /* Debug */,
351 | C129DAD71F8572780007C8CE /* Release */,
352 | );
353 | defaultConfigurationIsVisible = 0;
354 | defaultConfigurationName = Release;
355 | };
356 | C129DAD81F8572780007C8CE /* Build configuration list for PBXNativeTarget "PJs" */ = {
357 | isa = XCConfigurationList;
358 | buildConfigurations = (
359 | C129DAD91F8572780007C8CE /* Debug */,
360 | C129DADA1F8572780007C8CE /* Release */,
361 | );
362 | defaultConfigurationIsVisible = 0;
363 | defaultConfigurationName = Release;
364 | };
365 | /* End XCConfigurationList section */
366 | };
367 | rootObject = C129DAC21F8572780007C8CE /* Project object */;
368 | }
369 |
--------------------------------------------------------------------------------