git.iko.soy/SourceDocsSwift
on master help sign in
3 files changed+145−26
since splitsnapshots
unifiedsplit
README.md+36 SourceDocsSwift/TeXer.swift+50−13 SourceDocsSwift/main.swift+59−13
README.md+36
@@ -1,3 +1,39 @@
11# SourceDocsSwift
22
33Генернирует LaTeX-таблицы всех классов, структур и их полей и методов из проекта Xcode для вставки в техническую документацию.
4+
5+## Установка
6+
7+```bash
8+brew install ilyakooo0/tap/sourceDocsSwift
9+```
10+
11+## Использование
12+
13+```bash
14+sourceDocsSwift -i path/to/XcodePrjectDirectory/ -o path/to/output/doc.tex -s latex -l 1
15+```
16+
17+```bash
18+sourceDocsSwift -s tech -l 2
19+```
20+
21+По умолчанию ищет проект в текущей папке и пишет результат в эту же папку в файл `doc.tex`.
22+
23+В LaTeX документ можно вставить просто положив рядом с щсновным `.tex` документом и вставив в нужное место:
24+
25+```LaTeX
26+\include{doc}
27+```
28+
29+Так же требуется пакет `longtable`. Если в вашем шаблоне этого еще нигде нет, то где-нибудь в преамбуле надо вставить:
30+
31+```LaTeX
32+\usepackage{longtable}
33+```
34+### Параметры
35+
36+- `[-s | --style] [latex | tech]` -- стиль команды самого внешнего уровня
37+- `[-l | --level] [1 | 2 | 3]` -- отступ в уровнях
38+- `[-i | --input] path/to/projectDirectory` -- путь к папке с проектом
39+- `[-o | --output] path/to/output.tex` -- путь к фалу, в который писать результат
SourceDocsSwift/TeXer.swift+50−13
@@ -7,26 +7,26 @@
77//
88
99struct TeXer {
10− static func convert(objects: [Object]) -> String {
10+ static func convert(objects: [Object], with style: TexType = .laTeX(2)) -> String {
1111 return """
12− \\subsection{Описание классов и структур}
12+ \\\(style.section(for: 1)){Описание классов и структур}
1313
14− \\begin{longtable}{|p{0.55\\textwidth} | p{0.4\\textwidth}|}
14+ \\begin{longtable}{| >{\\raggedright\\arraybackslash}p{0.55\\textwidth} | p{0.4\\textwidth}|}
1515 \\hline
1616 \\textbf{Класс или стркура} & \\textbf{Описание} \\\\ \\hline
17− \( objects.map {"\\texttt{\($0.declaration)} & \($0.documentation ?? "{\\color{red} TODO}") \\\\ \\hline"} .joined(separator: "\n") )
17+ \( objects.map {"\\texttt{\($0.declaration)} & {\\color{red} TODO} \\\\ \\hline"} .joined(separator: "\n") )
1818 \\end{longtable}
19−
2019
21− \\subsection{Описание полей классов и структур}
20+
21+ \\\(style.section(for: 1)){Описание полей классов и структур}
2222
2323 \(
2424 objects.compactMap {
2525 if $0.fields.count > 0 {
2626 return """
27− \\subsubsection{\\texttt{\($0.declaration)}}
27+ \\\(style.section(for: 2))*{\\texttt{\($0.declaration)}}
2828
29− \\begin{longtable}{|p{0.55\\textwidth} | p{0.4\\textwidth}|}
29+ \\begin{longtable}{| >{\\raggedright\\arraybackslash}p{0.55\\textwidth} | p{0.4\\textwidth}|}
3030 \\hline
3131 \\textbf{Поле} & \\textbf{Описание} \\\\ \\hline
3232 \( $0.fields.map {"\\texttt{\($0.declaration.prefix {$0 != "="})} & {\\color{red} TODO} \\\\ \\hline"} .joined(separator: "\n") )
@@ -38,19 +38,19 @@ struct TeXer {
3838 }
3939 } .joined(separator: "\n")
4040 )
41−
42− \\subsection{Описание методов классов и структур}
41+
42+ \\\(style.section(for: 1)){Описание методов классов и структур}
4343
4444 \(
4545 objects.compactMap {
4646 if $0.methods.count > 0 {
4747 return """
48− \\subsubsection{\\texttt{\($0.declaration)}}
48+ \\\(style.section(for: 2))*{\\texttt{\($0.declaration)}}
4949
50− \\begin{longtable}{|p{0.55\\textwidth} | p{0.4\\textwidth}|}
50+ \\begin{longtable}{| >{\\raggedright\\arraybackslash}p{0.55\\textwidth} | p{0.4\\textwidth}|}
5151 \\hline
5252 \\textbf{Метод} & \\textbf{Описание} \\\\ \\hline
53− \( $0.methods.map {"\\texttt{\($0.declaration)} & \($0.documentation ?? "{\\color{red} TODO}") \\\\ \\hline"} .joined(separator: "\n") )
53+ \( $0.methods.map {"\\texttt{\($0.declaration)} & {\\color{red} TODO} \\\\ \\hline"} .joined(separator: "\n") )
5454 \\end{longtable}
5555
5656 """
@@ -61,4 +61,41 @@ struct TeXer {
6161 )
6262 """
6363 }
64+
65+ enum TexType {
66+ case techDoc(Int)
67+ case laTeX(Int)
68+
69+ func section(`for` level: Int) -> String {
70+ switch self {
71+ case .laTeX(let i):
72+ return String(repeating: "sub", count: i+level-2).appending("section")
73+ case .techDoc(let i):
74+ switch i+level-2 {
75+ case 0:
76+ return "addition"
77+ default:
78+ return TexType.laTeX(i).section(for: level)
79+ }
80+ }
81+ }
82+ var levelOffset: Int {
83+ get {
84+ switch self {
85+ case .laTeX(let i):
86+ return i
87+ case .techDoc(let i):
88+ return i
89+ }
90+ }
91+ set {
92+ switch self {
93+ case .laTeX(_):
94+ self = .laTeX(newValue)
95+ case .techDoc(_):
96+ self = .techDoc(newValue)
97+ }
98+ }
99+ }
100+ }
64101}
SourceDocsSwift/main.swift+59−13
@@ -8,36 +8,76 @@
88
99import Foundation
1010
11−//let directory = "/Users/ilya/Developer/Dotrix/Dotrix/"
12−//let output = "/Users/ilya/Desktop/foo.tex"
13−
1411let args = Array(CommandLine.arguments.dropFirst())
15−let temp = FileManager.default.temporaryDirectory.appendingPathComponent("SourceDocsSwift/build\(Date().timeIntervalSince1970)")
16−
17−print(temp)
12+//let temp = FileManager.default.temporaryDirectory.appendingPathComponent("SourceDocsSwift/build\(Date().timeIntervalSince1970)", isDirectory: true)
1813
1914var output = "docs.tex"
2015var directory: String?
16+var style: TeXer.TexType = .laTeX(2)
2117
2218var i = 0
2319while i < args.count {
2420 switch args[i] {
25− case "-o":
21+ case "-o", "--output":
2622 if i + 1 < args.count {
2723 i += 1
2824 output = args[i]
2925 }
30− case "-i":
26+ case "-i", "--input":
3127 if i + 1 < args.count {
3228 i += 1
3329 directory = args[i]
3430 }
31+ case "-s", "--style":
32+ if i + 1 < args.count {
33+ i += 1
34+ switch args[i].lowercased() {
35+ case "latex", "xetex", "tex":
36+ style = .laTeX(style.levelOffset)
37+ case "tech", "techdoc", "techdocs":
38+ style = .techDoc(style.levelOffset)
39+ default:
40+ print("""
41+ That is not a valid style.
42+
43+ Valid styles are:
44+ latex
45+ techdoc
46+ """)
47+ exit(1)
48+ }
49+ }
50+ case "-l", "--level":
51+ if i + 1 < args.count {
52+ i += 1
53+ guard let l = Int(args[i]) else {
54+ print("""
55+ That is not a valid int.
56+ """)
57+ exit(1)
58+ }
59+ if l < 1 {
60+ print("""
61+ Level must be greater or equal to 1.
62+ """)
63+ exit(1)
64+ }
65+ style.levelOffset = l
66+ }
3567 default:
3668 break
3769 }
3870 i += 1
3971}
4072
73+var outputIsDirectory: ObjCBool = false
74+
75+FileManager.default.fileExists(atPath: output, isDirectory: &outputIsDirectory)
76+
77+if outputIsDirectory.boolValue {
78+ output.append("/docs.tex")
79+}
80+
4181let decoder = JSONDecoder()
4282
4383guard let xcbTagetData = Shell.launch(executable: "/usr/bin/xcodebuild", arguments: ["-list", "-json"], launchDirectory: directory) else {
@@ -59,8 +99,8 @@ let targets = xcbResponse.targets
5999var files: [String: [Object]] = [:]
60100
61101for target in targets {
62− try? FileManager.default.removeItem(at: temp)
63− guard let skResponseData = Shell.launch(executable: "/usr/local/bin/sourcekitten", arguments: ["doc", "--", "-target", target, "CONFIGURATION_BUILD_DIR=\(temp)"], launchDirectory: directory) else {
102+// try? FileManager.default.removeItem(at: temp)
103+ guard let skResponseData = Shell.launch(executable: "/usr/local/bin/sourcekitten", arguments: ["doc", "--", "-target", target], launchDirectory: directory) else {
64104 print("""
65105 Make sure sourcekitten is installed
66106
@@ -80,9 +120,15 @@ for target in targets {
80120
81121
82122
83−let tex = TeXer.convert(objects: files.flatMap {$0.value})
84−
85−try? tex.write(toFile: output, atomically: true, encoding: .utf8)
123+let tex = TeXer.convert(objects: files.flatMap {$0.value}, with: style)
124+do {
125+ try tex.write(toFile: output, atomically: true, encoding: .utf8)
126+} catch {
127+ print("""
128+ There was an error writing the outuput file.
129+ """)
130+ exit(1)
131+}
86132
87133print("""
88134+-------+