]> gitweb.factorcode.org Git - factor.git/blob - basis/help/lint/checks/checks.factor
Support multiline entries in the UI Listener
[factor.git] / basis / help / lint / checks / checks.factor
1 ! Copyright (C) 2009 Slava Pestov.
2 ! See https://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays assocs classes classes.struct
4 classes.tuple combinators combinators.short-circuit debugger
5 definitions effects eval formatting grouping help help.markup
6 help.topics io io.streams.string kernel macros math
7 math.statistics namespaces prettyprint sequences sequences.deep
8 sets splitting strings summary tools.destructors unicode vocabs
9 vocabs.loader words words.constant words.symbol ;
10 IN: help.lint.checks
11
12 ERROR: simple-lint-error message ;
13
14 M: simple-lint-error summary message>> ;
15
16 M: simple-lint-error error. summary print ;
17
18 SYMBOL: vocabs-quot
19 SYMBOL: vocab-articles
20
21 : no-ui-disposables ( seq -- seq' )
22     [
23         class-of name>> {
24             "single-texture" "multi-texture" ! opengl.textures
25             "line" ! core-text
26             "layout" ! ui.text.pango
27             "script-string" ! windows.uniscribe
28             "linux-monitor" ! github issue #2014, race condition in disposing of child monitors
29             "event-stream"
30             "macosx-monitor"
31             "recursive-monitor"
32             "input-port"
33             "malloc-ptr"
34             "fd"
35         } member?
36     ] reject ;
37
38 : check-example ( element -- )
39     [
40         '[
41             _ rest [
42                 but-last join-lines
43                 (eval-with-stack>string)
44                 "\n" ?tail drop
45             ] keep
46             last assert=
47         ] vocabs-quot get call( quot -- )
48     ] leaks members no-ui-disposables
49     dup length 0 > [
50         dup [ class-of ] histogram-by
51         [ "Leaked resources: " write ... ] with-string-writer simple-lint-error
52     ] [
53         drop
54     ] if ;
55
56 : check-examples ( element -- )
57     \ $example swap elements [ check-example ] each ;
58
59 : extract-values ( element -- seq )
60     \ $values swap elements
61     [ f ] [ first rest keys ] if-empty ;
62
63 : extract-value-effects ( element -- seq )
64     \ $values swap elements [ f ] [
65         first rest [
66             \ $quotation swap elements [ f ] [
67                 first second dup effect? [ effect>string ] when
68             ] if-empty
69         ] map
70     ] if-empty ;
71
72 : effect-values ( word -- seq )
73     stack-effect
74     [ in>> ] [ out>> ] bi append
75     [ dup pair? [ first ] when effect>string ] map members ;
76
77 : effect-effects ( word -- seq )
78     stack-effect in>> [
79         dup pair?
80         [ second dup effect? [ effect>string ] [ drop f ] if ]
81         [ drop f ] if
82     ] map ;
83
84 : contains-funky-elements? ( element -- ? )
85     {
86         $shuffle
87         $values-x/y
88         $predicate
89         $class-description
90         $error-description
91     } swap '[ _ elements empty? not ] any? ;
92
93 : don't-check-word? ( word -- ? )
94     {
95         [ macro? ]
96         [ symbol? ]
97         [ parsing-word? ]
98         [ "declared-effect" word-prop not ]
99         [ constant? ]
100         [ "help" word-prop not ]
101     } 1|| ;
102
103 : skip-check-values? ( word element -- ? )
104     [ don't-check-word? ] [ contains-funky-elements? ] bi* or ;
105
106 : check-values ( word element -- )
107     2dup skip-check-values? [ 2drop ] [
108         [ effect-values ] [ extract-values ] bi* 2dup
109         sequence= [ 2drop ] [
110             "$values don't match stack effect; expected %u, got %u" sprintf
111             simple-lint-error
112         ] if
113     ] if ;
114
115 : check-value-effects ( word element -- )
116     [ effect-effects ] [ extract-value-effects ] bi*
117     [ 2dup and [ = ] [ 2drop t ] if ] 2all? [
118         "$quotation stack effects in $values don't match"
119         simple-lint-error
120     ] unless ;
121
122 : check-see-also ( element -- )
123     \ $see-also swap elements [ rest all-unique? ] all?
124     [ "$see-also are not unique" simple-lint-error ] unless ;
125
126 : check-modules ( element -- )
127     \ $vocab-link swap elements [
128         second
129         dup vocab-exists? [ drop ] [
130             "$vocab-link to non-existent vocabulary ``" "''" surround
131             simple-lint-error
132         ] if
133     ] each ;
134
135 : check-slots-tables ( element -- )
136     \ $slots swap elements [ rest [ length 2 = ] all?  ] all?
137     [ "$slots have too many values in at least one row" simple-lint-error ] unless ;
138
139 : check-rendering ( element -- )
140     [ print-content ] with-string-writer drop ;
141
142 : check-strings ( str -- )
143     [
144         "\n\t" intersects? [
145             "Paragraph text should not contain \\n or \\t"
146             simple-lint-error
147         ] when
148     ] [
149         "  " subseq-of? [
150             "Paragraph text should not contain double spaces"
151             simple-lint-error
152         ] when
153     ] bi ;
154
155 : check-whitespace ( str1 str2 -- )
156     2dup [ ?last " (" member? ] [ ?first " ).,;:" member? ] bi* or
157     [ 2drop ] [
158         "Missing whitespace between strings ``%s'' and ``%s''"
159         sprintf simple-lint-error
160     ] if ;
161
162 : check-bogus-nl ( element -- )
163     { { $nl } { { $nl } } } [ head? ] with any? [
164         "Simple element should not begin with a paragraph break"
165         simple-lint-error
166     ] when ;
167
168 : extract-slots ( elements -- seq )
169     [ dup pair? [ first \ $slot = ] [ drop f ] if ] deep-filter
170     [ second ] map ;
171
172 : check-class-description ( word element -- )
173     \ $class-description swap elements over class? [
174         [
175             dup struct-class? [ struct-slots ] [ all-slots ] if
176             [ name>> ] map
177         ] [ extract-slots ] bi*
178         [ swap member? ] with reject [
179             ", " join "Described $slot does not exist: " prepend
180             simple-lint-error
181         ] unless-empty
182     ] [
183         nip empty? not [
184             "A word that is not a class has a $class-description"
185             simple-lint-error
186         ] when
187     ] if ;
188
189 : check-article-title ( article -- )
190     article-title first LETTER?
191     [ "Article title must begin with a capital letter" simple-lint-error ] unless ;
192
193 : check-elements ( element -- )
194     {
195         [ check-bogus-nl ]
196         [ [ string? ] filter [ check-strings ] each ]
197         [ [ simple-element? ] filter [ check-elements ] each ]
198         [ 2 <clumps> [ [ string? ] all? ] filter [ first2 check-whitespace ] each ]
199     } cleave ;
200
201 : check-descriptions ( element -- )
202     { $description $class-description $var-description }
203     swap '[
204         _ elements [
205             rest { { } { "" } } member?
206             [ "Empty $description" simple-lint-error ] when
207         ] each
208     ] each ;
209
210 : check-markup ( element -- )
211     {
212         [ check-elements ]
213         [ check-rendering ]
214         [ check-examples ]
215         [ check-modules ]
216         [ check-descriptions ]
217         [ check-slots-tables ]
218     } cleave ;
219
220 : files>vocabs ( -- assoc )
221     loaded-vocab-names
222     [ [ [ vocab-docs-path ] keep ] H{ } map>assoc ]
223     [ [ [ vocab-source-path ] keep ] H{ } map>assoc ]
224     bi assoc-union ;
225
226 : group-articles ( -- assoc )
227     articles get keys
228     files>vocabs
229     H{ } clone [
230         '[
231             dup >link where dup
232             [ first _ at _ push-at ] [ 2drop ] if
233         ] each
234     ] keep ;
235
236 : all-word-help ( words -- seq )
237     [ word-help ] filter ;