@@ -317,24 +317,82 @@ get_edoc_chunk(M, Uri) ->
317
317
% % edoc in Erlang/OTP 24 and later can create doc chunks for edoc
318
318
case {code :ensure_loaded (edoc_doclet_chunks ), code :ensure_loaded (edoc_layout_chunks )} of
319
319
{{module , _ }, {module , _ }} ->
320
- Path = els_uri :path (Uri ),
321
- Dir = erlang_ls :cache_root (),
322
- ok = edoc :run (
323
- [els_utils :to_list (Path )],
324
- [
325
- {doclet , edoc_doclet_chunks },
326
- {layout , edoc_layout_chunks },
327
- {dir , Dir }
328
- | edoc_options ()
329
- ]
330
- ),
331
- Chunk = filename :join ([Dir , " chunks" , atom_to_list (M ) ++ " .chunk" ]),
332
- {ok , Bin } = file :read_file (Chunk ),
333
- {ok , binary_to_term (Bin )};
320
+ case edoc_run (Uri ) of
321
+ ok ->
322
+ {ok , Bin } = file :read_file (chunk_file_path (M )),
323
+ {ok , binary_to_term (Bin )};
324
+ error ->
325
+ error
326
+ end ;
334
327
E ->
335
328
? LOG_DEBUG (" [edoc_chunk] load error" , [E ]),
336
329
error
337
330
end .
331
+
332
+ -spec chunk_file_path (module ()) -> file :filename_all ().
333
+ chunk_file_path (M ) ->
334
+ Dir = erlang_ls :cache_root (),
335
+ filename :join ([Dir , " chunks" , atom_to_list (M ) ++ " .chunk" ]).
336
+
337
+ -spec is_chunk_file_up_to_date (binary (), module ()) -> boolean ().
338
+ is_chunk_file_up_to_date (Path , Module ) ->
339
+ ChunkPath = chunk_file_path (Module ),
340
+ filelib :is_file (ChunkPath ) andalso
341
+ filelib :last_modified (ChunkPath ) > filelib :last_modified (Path ).
342
+
343
+ -spec edoc_run (uri ()) -> ok | error .
344
+ edoc_run (Uri ) ->
345
+ Ref = make_ref (),
346
+ Module = els_uri :module (Uri ),
347
+ Path = els_uri :path (Uri ),
348
+ Opts = [
349
+ {doclet , edoc_doclet_chunks },
350
+ {layout , edoc_layout_chunks },
351
+ {dir , erlang_ls :cache_root ()}
352
+ | edoc_options ()
353
+ ],
354
+ Parent = self (),
355
+ case is_chunk_file_up_to_date (Path , Module ) of
356
+ true ->
357
+ ? LOG_DEBUG (" Chunk file is up to date!" ),
358
+ ok ;
359
+ false ->
360
+ % % Run job to generate chunk file
361
+ % % This can be slow, run it in a spawned process so
362
+ % % we can timeout
363
+ spawn_link (
364
+ fun () ->
365
+ Name = list_to_atom (lists :concat (['docs_' , Module ])),
366
+ try
367
+ % % Use register to ensure we only run one of these
368
+ % % processes at the same time.
369
+ true = register (Name , self ()),
370
+ ? LOG_DEBUG (" Generating doc chunks for ~s ." , [Module ]),
371
+ Res = edoc :run ([els_utils :to_list (Path )], Opts ),
372
+ ? LOG_DEBUG (" Done generating doc chunks for ~s ." , [Module ]),
373
+ Parent ! {Ref , Res }
374
+ catch
375
+ _ :Err :St ->
376
+ ? LOG_INFO (
377
+ " Generating do chunks for ~s failed: ~p \n ~p " ,
378
+ [Module , Err , St ]
379
+ ),
380
+ % % Respond to parent with error
381
+ Parent ! {Ref , error }
382
+ end
383
+ end
384
+ ),
385
+ receive
386
+ {Ref , Res } ->
387
+ Res
388
+ after 1000 ->
389
+ % % This took too long, return and let job continue
390
+ % % running in background in order to let it generate
391
+ % % a chunk file
392
+ error
393
+ end
394
+ end .
395
+
338
396
-else .
339
397
-dialyzer ({no_match , function_docs / 5 }).
340
398
-dialyzer ({no_match , type_docs / 5 }).
0 commit comments