Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a timeout for LSP auto-format #1639

Open
antoyo opened this issue Feb 9, 2022 · 7 comments
Open

Add a timeout for LSP auto-format #1639

antoyo opened this issue Feb 9, 2022 · 7 comments
Labels
A-helix-term Area: Helix term improvements C-bug Category: This is a bug E-easy Call for participation: Experience needed to fix: Easy / not much E-good-first-issue Call for participation: Issues suitable for new contributors

Comments

@antoyo
Copy link
Contributor

antoyo commented Feb 9, 2022

Reproduction steps

I'm not sure exactly what it takes for this to happen, but I used the write command on a Rust file and the changes were not reflected automatically on disk. It could take +10 seconds.

From the logs, it looks like it might have been waiting for the LSP to do the formatting, but failed.

Environment

  • Platform: Linux
  • Terminal emulator: Alacritty
  • Helix version: helix v0.6.0
~/.cache/helix/helix.log
2022-02-09T10:24:25.775 helix_lsp::transport [ERROR] err <- "thread 'main' panicked at 'no value set for FileSourceRootQuery(FileId(8266))', /build/.cargo/registry/src/gh.neting.cc-1ecc6299db9ec823/salsa-0.17.0-pre.2/src/input.rs:106:32\n"
2022-02-09T10:24:25.775 helix_lsp::transport [ERROR] err <- "stack backtrace:\n"
2022-02-09T10:24:25.776 helix_lsp::transport [ERROR] err <- "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
2022-02-09T10:24:27.575 helix_lsp::transport [ERROR] err: <- StreamClosed
2022-02-09T10:24:27.575 helix_lsp::transport [ERROR] err: <- StreamClosed
2022-02-09T10:25:11.703 helix_lsp::transport [ERROR] err: <- IO(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })
2022-02-09T10:25:11.968 helix_lsp::transport [ERROR] err: <- IO(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })
[snip…]
2022-02-09T10:28:18.891 helix_lsp::transport [ERROR] err: <- IO(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })
2022-02-09T10:28:38.893 helix_view::document [WARN] LSP formatting failed: request timed out
2022-02-09T10:28:38.895 helix_lsp::transport [ERROR] err: <- IO(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })
2022-02-09T10:29:25.808 helix_lsp::transport [ERROR] err: <- IO(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })
2022-02-09T10:29:25.960 helix_lsp::transport [ERROR] err: <- IO(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })
2022-02-09T10:29:27.233 helix_lsp::transport [ERROR] err: <- IO(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })
2022-02-09T10:29:29.267 helix_lsp::transport [ERROR] err: <- IO(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })
2022-02-09T10:29:47.706 helix_lsp::transport [ERROR] err: <- IO(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })
2022-02-09T10:29:49.268 helix_view::document [WARN] LSP formatting failed: request timed out
2022-02-09T10:29:49.270 helix_lsp::transport [ERROR] err: <- IO(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })
2022-02-09T10:29:55.286 helix_lsp::transport [ERROR] err: <- IO(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })
2022-02-09T10:30:07.708 helix_view::document [WARN] LSP formatting failed: request timed out
2022-02-09T10:30:07.716 helix_lsp::transport [ERROR] err: <- IO(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })
2022-02-09T10:31:04.113 helix_lsp::transport [ERROR] err: <- IO(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })
2022-02-09T10:31:04.614 helix_term::application [ERROR] Timed out waiting for language servers to shutdown
@antoyo antoyo added the C-bug Category: This is a bug label Feb 9, 2022
@EpocSquadron
Copy link
Contributor

As a workaround, you can disable auto-format for rust in your ~/.config/helix/languages.toml as shown in the docs .

You might want to run helix with the -v flag to output to a debug file and see why it is failing to format as well.

@sudormrfbin
Copy link
Member

Should we also have a timeout for formatting ?

@hazeycode
Copy link
Contributor

Should we also have a timeout for formatting ?

Definitely. But further, should the file just be written anyway? Then try auto-format and overwrite if if was successful within the timeout period?

also see #2059 (comment)

@dead10ck
Copy link
Member

dead10ck commented Aug 10, 2022

@antoyo This definitely looks like there's an issue with your LSP. However, this does suggest that in general, it would be good to add the ability to add timeouts to the async jobs. I don't know if there are any type landmines here, but it could be simple to just add a Duration member to Job and a with_timeout method.

Should we just rename this issue to track that work? I'd be happy to pick that up after my open PR is closed, I expect it would be a quick change.

@the-mikedavis the-mikedavis changed the title It takes time for the file to be written to disk Add a timeout for LSP auto-format Aug 10, 2022
@kirawi kirawi added E-easy Call for participation: Experience needed to fix: Easy / not much E-good-first-issue Call for participation: Issues suitable for new contributors labels Dec 11, 2022
@ValouBambou
Copy link

Is there someone working on this issue at the moment ? If not I can try to fix it as the solution suggested by @dead10ck seems reasonable and relatively easy to implement.

@kirawi
Copy link
Member

kirawi commented Jan 11, 2024

I think we do actually have a timeout mechanism:

// TODO: delay other calls until initialize success
timeout(Duration::from_secs(timeout_secs), rx.recv())
.await
.map_err(|_| Error::Timeout(id))? // return Timeout
.ok_or(Error::StreamClosed)?
}

We also write regardless of whether formatting was successful:

async fn make_format_callback(
doc_id: DocumentId,
doc_version: i32,
view_id: ViewId,
format: impl Future<Output = Result<Transaction, FormatterError>> + Send + 'static,
write: Option<(Option<PathBuf>, bool)>,
) -> anyhow::Result<job::Callback> {
let format = format.await;
let call: job::Callback = Callback::Editor(Box::new(move |editor| {
if !editor.documents.contains_key(&doc_id) || !editor.tree.contains(view_id) {
return;
}
let scrolloff = editor.config().scrolloff;
let doc = doc_mut!(editor, &doc_id);
let view = view_mut!(editor, view_id);
if let Ok(format) = format {
if doc.version() == doc_version {
doc.apply(&format, view.id);
doc.append_changes_to_history(view);
doc.detect_indent_and_line_ending();
view.ensure_cursor_in_view(doc, scrolloff);
} else {
log::info!("discarded formatting changes because the document changed");
}
}
if let Some((path, force)) = write {
let id = doc.id();
if let Err(err) = editor.save(id, path, force) {
editor.set_error(format!("Error saving: {}", err));
}
}
}));
Ok(call)
}

@pascalkuthe
Copy link
Member

yeah the timeout is just pretty long by default (20s) and apply equally to all LSP operations. We could look at how VSCode handles that (default timeout, different timeouts for different operations, what is the default for those operations that have dedicated timeouts)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-helix-term Area: Helix term improvements C-bug Category: This is a bug E-easy Call for participation: Experience needed to fix: Easy / not much E-good-first-issue Call for participation: Issues suitable for new contributors
Projects
None yet
Development

No branches or pull requests

8 participants