diff --git a/NEWREADME.md b/NEWREADME.md index 8744cd1..b2cc97e 100644 --- a/NEWREADME.md +++ b/NEWREADME.md @@ -134,7 +134,6 @@ You can see in which language an app is written. Currently there are following l ### Development #### Git - - [Cashew](https://github.com/simplerocket-llc/OpenCashew) - Cashew macOS Github Issue Tracker. ![c_icon] ![objective_c_icon] - [GPM](https://github.com/mtgto/GPM) - macOS application for easily operating GitHub Projects. ![swift_icon] - [GitSync](https://github.com/eonist/GitSync) - Minimalistic Git client for Mac. ![swift_icon]
Screenshots

@@ -149,16 +148,13 @@ You can see in which language an app is written. Currently there are following l - [Xit](https://github.com/Uncommon/Xit) - Xit is a graphical tool for working with git repositories. ![swift_icon]
Screenshots

#### JSON Parsing - - [JSONExport](https://github.com/Ahmed-Ali/JSONExport) - Desktop application for macOS which enables you to export JSON objects as model classes with their associated constructors, utility methods, setters and getters in your favorite language. ![swift_icon]
Screenshots

- [j2s](https://github.com/zadr/j2s) - macOS app to convert JSON objects into Swift structs (currently targets Swift 4 and Codable). ![swift_icon] #### Other - - [vegvisir](https://github.com/ant4g0nist/vegvisir) - Browser based GUI for **LLDB** Debugger. ![javascript_icon]
Screenshots

#### Web Development - - [Insomnia](https://github.com/getinsomnia/insomnia) - Insomnia is a cross-platform REST client, built on top of Electron. ![javascript_icon]
Screenshots

- [KubeMonitor](https://github.com/DanSanche/KubeMonitor) - KubeMonitor is a macOS app that displays information about your active Kubernetes cluster in your menu bar. ![swift_icon]
Screenshots

- [Lantern](https://github.com/BurntCaramel/Lantern) - Dedicated Mac app for website auditing and crawling. ![swift_icon] @@ -169,7 +165,6 @@ You can see in which language an app is written. Currently there are following l - [stts](https://github.com/inket/stts) - macOS app for monitoring the status of cloud services. ![swift_icon]
Screenshots

#### iOS / macOS - - [Alloy](https://github.com/alexlee002/alloy) - Simple toolkit that makes your ios-macos-development apps development more easier. ![objective_c_icon] - [AppBox](https://github.com/vineetchoudhary/AppBox-iOSAppsWirelessInstallation) - Tool for iOS developers to build and deploy Development, Ad-Hoc and In-house (Enterprise) applications directly to the devices from your Dropbox account. ![objective_c_icon] - [AppIcons](https://github.com/kuyawa/AppIcons) - Tool for generating icons in all sizes as required by macOS and iOS apps. ![swift_icon]
Screenshots

@@ -204,26 +199,21 @@ You can see in which language an app is written. Currently there are following l ### Editors #### CSV - - [TableTool](https://github.com/jakob/TableTool) - simple CSV editor for the macOS. ![objective_c_icon] #### JSON - - [JSON-Splora](https://github.com/wellsjo/JSON-Splora) - GUI for editing, visualizing, and manipulating JSON data. ![javascript_icon] #### Markdown - - [Gingko](https://github.com/gingko/client) - Tree-structured markdown editor for macOS, Windows, and Linux. ![elm_icon]
Screenshots

- [MacDown](https://github.com/MacDownApp/macdown) - Markdown editor for macOS. ![objective_c_icon] - [Mark Text](https://github.com/marktext/marktext) - Realtime preview markdown editor for macOS Windows and Linux. ![javascript_icon] - [Twig](https://github.com/lukakerr/twig) - A modern MacOS markdown editor. ![swift_icon]
Screenshots

#### TeX - - [Qilin Editor](https://github.com/qilin-editor/qilin-app) - Text editor for exact sciences with built-in KaTeX/AsciiMath support. ![javascript_icon] #### Text - - [CotEditor](https://github.com/coteditor/CotEditor) - Lightweight Plain-Text Editor for macOS. ![swift_icon]
Screenshots

- [MacVim](https://github.com/macvim-dev/macvim) - Text editor for macOS. ![c_icon] - [Noto](https://github.com/brunophilipe/noto) - Plain text editor for macOS with customizable themes. ![swift_icon]
Screenshots

diff --git a/ReadmeGenerator.swift b/ReadmeGenerator.swift new file mode 100644 index 0000000..2fff504 --- /dev/null +++ b/ReadmeGenerator.swift @@ -0,0 +1,309 @@ +// +// ReadmeGenerator.swift +// awesome-mac-os-apps-helper +// +// Created by Serhii Londar on 11/12/18. +// + +import Foundation + +let header = """ +

+ +

+ +# Awesome macOS open source applications + +

+Awesome +Join the chat at gitter +

+ +## Support +Hey friend! Help me out for a couple of :beers:! Patreon donate button + + +List of awesome open source applications for macOS. This list contains a lot of native, and cross-platform apps. The main goal of this repository is to find free open source apps and start contributing. Feel free to [contribute](CONTRIBUTING.md) to the list, any suggestions are welcome! + +You can see in which language an app is written. Currently there are following languages: + +- ![c_icon] - C language. +- ![cpp_icon] - C++ language. +- ![c_sharp_icon] - C# language. +- ![clojure_icon] - Clojure language. +- ![coffee_script_icon] - CoffeeScript language. +- ![css_icon] - CSS language. +- ![elm_icon] - Elm language. +- ![haskell_icon] - Haskell language. +- ![javascript_icon] - JavaScript language. +- ![lua_icon] - Lua language. +- ![objective_c_icon] - Objective-C language. +- ![python_icon] - Python language. +- ![ruby_icon] - Ruby language. +- ![rust_icon] - Rust language. +- ![swift_icon] - Swift language. +- ![type_script_icon] - TypeScript language. + + +## Contents +- [Audio](#audio) +- [Backup](#backup) +- [Browser](#browser) +- [Chat](#chat) +- [Cryptocurrency](#cryptocurrency) +- [Database](#database) +- [Development](#development) + - [Git](#git) + - [iOS / macOS](#ios--macos) + - [JSON Parsing](#json-parsing) + - [Web development](#web-development) + - [Other](#other) +- [Downloader](#downloader) +- [Editors](#editors) + - [CSV](#csv) + - [JSON](#json) + - [Markdown](#markdown) + - [TeX](#tex) + - [Text](#text) +- [Extensions](#extensions) +- [Finder](#finder) +- [Games](#games) +- [Graphics](#graphics) +- [IDE](#ide) +- [Images](#images) +- [Keyboard](#keyboard) +- [Mail](#mail) +- [Menubar](#menubar) +- [Music](#music) +- [News](#news) +- [Notes](#notes) +- [Other](#other-1) +- [Podcast](#podcast) +- [Productivity](#productivity) +- [Screensaver](#screensaver) +- [Security](#security) +- [Sharing Files](#sharing-files) +- [Social Networking](#social-networking) +- [Streaming](#streaming) +- [System](#system) +- [Terminal](#terminal) +- [Utilities](#utilities) +- [VPN & Proxy](#vpn--proxy) +- [Video](#video) +- [Wallpaper](#wallpaper) +- [Window Management](#window-management) + +## Applications + +""" + +let footer = """ + +## Contributors + +Thanks to all the people who contribute: + + + +[app_store]: ./icons/app_store-16.png 'App Store.' +[c_icon]: ./icons/c-16.png 'C language.' +[cpp_icon]: ./icons/cpp-16.png 'C++ language.' +[c_sharp_icon]: ./icons/csharp-16.png 'C# Language' +[clojure_icon]: ./icons/clojure-16.png 'Clojure Language' +[coffee_script_icon]: ./icons/coffeescript-16.png 'CoffeeScript language.' +[css_icon]: ./icons/css-16.png 'CSS language.' +[elm_icon]: ./icons/elm-16.png 'Elm Language' +[haskell_icon]: ./icons/haskell-16.png 'Haskell language.' +[java_icon]: ./icons/java-16.png 'Java language.' +[javascript_icon]: ./icons/javascript-16.png 'JavaScript language.' +[lua_icon]: ./icons/Lua-16.png 'Lua language.' +[objective_c_icon]: ./icons/objective-c-16.png 'Objective-C language.' +[python_icon]: ./icons/python-16.png 'Python language.' +[ruby_icon]: ./icons/ruby-16.png 'Ruby language.' +[rust_icon]: ./icons/rust-16.png 'Rust language.' +[swift_icon]: ./icons/swift-16.png 'Swift language.' +[type_script_icon]: ./icons/typescript-16.png 'TypeScript language.' +""" +class JSONApplications: Codable { + let applications: [JSONApplication] + + enum CodingKeys: String, CodingKey { + case applications + } + + init(applications: [JSONApplication]) { + self.applications = applications + } + + required public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + applications = try values.decodeIfPresent([JSONApplication].self, forKey: .applications) ?? [] + } +} + +class JSONApplication: Codable { + var title: String + var repoURL: String + var shortDescription: String + var languages: [String] + var screenshots: [String] + var category: String + + enum CodingKeys: String, CodingKey { + case title + case repoURL = "repo_url" + case shortDescription = "short_description" + case languages + case screenshots + case category + } + + init(title: String, repoURL: String, shortDescription: String, languages: [String], screenshots: [String], category: String) { + self.title = title + self.repoURL = repoURL + self.shortDescription = shortDescription + self.languages = languages + self.screenshots = screenshots + self.category = category + } +} + +class Categories: Codable { + let categories: [Category] + + init(categories: [Category]) { + self.categories = categories + } + + required public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + categories = try values.decodeIfPresent([Category].self, forKey: .categories) ?? [] + } +} + +class Category: Codable { + let title, id, description: String + let parent: String? + + init(title: String, id: String, description: String, parent: String?) { + self.title = title + self.id = id + self.description = description + self.parent = parent + } +} + +class ReadmeGenerator { + var readmeString = String.empty + + func generateReadme() { + print("Start") + guard let applicationsData = try? Data(contentsOf: URL(fileURLWithPath: FilePaths.applications.rawValue)) else { return } + guard let categoriesData = try? Data(contentsOf: URL(fileURLWithPath: FilePaths.categories.rawValue)) else { return } + let jsonDecoder = JSONDecoder() + guard let applicationsObject = try? jsonDecoder.decode(JSONApplications.self, from: applicationsData) else { return } + guard let categoriesObject = try? jsonDecoder.decode(Categories.self, from: categoriesData) else { return } + + var categories = categoriesObject.categories + let subcategories = categories.filter({ $0.parent != nil && !$0.parent!.isEmpty }) + var applications = applicationsObject.applications + + for subcategory in subcategories { + if let index = categories.lastIndex(where: { $0.parent != subcategory.id }) { + categories.remove(at: index) + } + } + + categories = categories.sorted(by: { $0.title < $1.title }) + + applications = applications.sorted(by: { $0.category < $1.category }) + + readmeString.append(header) + + for category in categories { + readmeString.append(String.enter + String.section + String.space + category.title + String.enter) + var categoryApplications = applications.filter({ $0.category == category.id }) + categoryApplications = categoryApplications.sorted(by: { $0.title < $1.title }) + + for application in categoryApplications { + readmeString.append(application.markdownDescription()) + readmeString.append(String.enter) + } + + var subcategories = subcategories.filter({ $0.parent == category.id }) + guard subcategories.count > 0 else { continue } + subcategories = subcategories.sorted(by: { $0.title < $1.title }) + for subcategory in subcategories { + readmeString.append(String.enter + String.subsection + String.space + subcategory.title + String.enter) + var categoryApplications = applications.filter({ $0.category == subcategory.id }) + categoryApplications = categoryApplications.sorted(by: { $0.title < $1.title }) + + for application in categoryApplications { + readmeString.append(application.markdownDescription()) + readmeString.append(String.enter) + } + } + } + readmeString.append(footer) + print(readmeString) + try? readmeString.data(using: .utf8)?.write(to: URL(fileURLWithPath: FilePaths.newReadme.rawValue)) + print("Finish") + } +} + +extension String { + static let empty = "" + static let space = " " + static let enter = "\n" + static let section = "###" + static let subsection = "####" +} + +extension JSONApplication { + func markdownDescription() -> String { + var markdownDescription = String.empty + var languages: String = String.empty + for lang in self.languages { + languages.append("![\(lang)] ") + } + + markdownDescription.append("- [\(self.title)](\(self.repoURL)) - \(self.shortDescription) \(languages)") + + if self.screenshots.count > 0 { + var screenshotsString = String.empty + screenshotsString += (String.space + Constants.detailsBeginString + String.space) + self.screenshots.forEach({ + screenshotsString += (String.space + (NSString(format: Constants.srcLinePattern as NSString, $0 as CVarArg) as String) + String.space) + }) + screenshotsString += (String.space + Constants.detailsEndString + String.space) + markdownDescription.append(screenshotsString) + } + return markdownDescription + } +} + +enum FilePaths: String { + case readme = "./README.md" + case newReadme = "./NEWREADME.md" + case applications = "./applications.json" + case categories = "./categories.json" +} + +struct Constants { + static let detailsBeginString = "
Screenshots

" + static let detailsEndString = "

" + static let srcLinePattern = "" + + static let startProcessString = "### Database" + static let endProcessString = "### Development" + + static func regex(for type: String) -> String { + return "\\((.+\\.\(type))" + } + static func regex1(for type: String) -> String { + return "\\\"(.+\\.\(type))" + } +} + + +ReadmeGenerator().generateReadme()