 : refresh-all ( -- ) "" refresh ;
 
 GENERIC: (load-vocab) ( name -- vocab )
-!
+
+: add-to-blacklist ( error vocab -- )
+    vocab-name blacklist get dup [ set-at ] [ 3drop ] if ;
+
 M: vocab (load-vocab)
-    dup vocab-root [
-        dup vocab-source-loaded? [ dup load-source ] unless
-        dup vocab-docs-loaded? [ dup load-docs ] unless
-    ] when ;
+    [
+        dup vocab-root [
+            dup vocab-source-loaded? [ dup load-source ] unless
+            dup vocab-docs-loaded? [ dup load-docs ] unless
+        ] when
+    ] [ [ swap add-to-blacklist ] keep rethrow ] recover ;
 
 M: string (load-vocab)
     [ ".private" ?tail drop reload ] keep vocab ;

M: vocab-link (load-vocab)
    vocab-name (load-vocab) ;

TUPLE: blacklisted-vocab name ;

: blacklisted-vocab ( name -- * )
    \ blacklisted-vocab construct-boa throw ;

M: blacklisted-vocab error.
    "This vocabulary depends on the " write
    blacklisted-vocab-name write
    " vocabulary which failed to load" print ;

[
    dup vocab-name blacklist get key? [
        vocab-name blacklisted-vocab
    ] [
        [
            dup vocab [ ] [ ] ?if (load-vocab)
        ] with-compiler-errors
    ] if
] load-vocab-hook set-global

: vocab-where ( vocab -- loc )

    [ load-error. nl ] each ;

SYMBOL: blacklist
SYMBOL: failures

: require-all ( vocabs -- failures )
    [
        V{ } clone blacklist set
        V{ } clone failures set
        [
            [ require ]
            [ swap vocab-name failures get set-at ]
            recover
        ] each
        failures get
    ] with-compiler-errors ;

: do-refresh ( modified-sources modified-docs -- )
