<div dir="auto"><div dir="auto">It would be great to get this feature upstreamed in some form.</div><div dir="auto"><br></div>From a pragmatic point of view, the JSON level seems by far the least invasive way to do this. (It's a shame the VFS approach didn't work out)<div dir="auto"><br></div><div dir="auto">We have the Transport abstraction (clangd/Transport.h) which should cut across all JSON messages sent over stdio (because sometimes they're sent over XPC instead!)</div><div dir="auto"><br></div><div dir="auto">I think it would be possible to write a wrapping Transport implementation that does path translation and delegates to another. WDYT?</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Jun 27, 2019, 1:47 AM William Wagner <<a href="mailto:wcwwagner@gmail.com">wcwwagner@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div dir="ltr"><span id="m_8031547381901639146gmail-docs-internal-guid-4c81518e-7fff-c610-4e7f-1126d4a2ce30"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap">Hello all,</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap">Sorry for the super long delay here! I’ve created a fork of upstream clangd that implements this path mapping behavior, and have been using it for the past couple months. As stated previously, the primary environment I’m using this in is clangd running inside a docker container, the editor running on the host, and the source files sync'ed between the two (via a volume mount). </span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap">I went with the most straightforward implementation (to me), which is editing the JSON messages directly, both for inbound and outbound messages. Basically, I’ve added the following:</span></p><ol style="margin-top:0pt;margin-bottom:0pt"><li dir="ltr" style="list-style-type:decimal;font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:11pt;background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap">A new --pathMappings string argument, which is of the form <host_path>:<remote_path>;<host_path>:<remote_path>...</span></p></li><li dir="ltr" style="list-style-type:decimal;font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:11pt;background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap">Logic to recursively loop through all the values in the JSON RPC messages, doing path substitution on all values that start with “file://” </span></p></li><li dir="ltr" style="list-style-type:decimal;font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:11pt;background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap">Calling this logic at all inbound locations (i.e. MessagesHandler::onNotify/onCall, etc.) and all outbound locations (i.e. ReplyOnce::Operator(), ClangdLSPServer::publishDiagnostics, etc)</span></p></li></ol><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap">This is something that works and is pretty useful to my team (and I hope others too). Does this sound reasonable to try and land in clangd? I’d be happy to code it up, but would just want some confirmation before going through the effort to do it properly. </span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap">Assuming it’s useful, I have some questions for the ideal implementation:</span></p><ol style="margin-top:0pt;margin-bottom:0pt"><li dir="ltr" style="list-style-type:decimal;font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:11pt;background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap">Should the path mappings be done on JSON values or the Protocol.h data structures? If it’s the latter, I suppose we could create something like `template <typename T> T doFilePathMappings(const T& Orig)`, and specialize the implementation for the protocol objects that have URIs in them.</span></p></li><li dir="ltr" style="list-style-type:decimal;font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:11pt;background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap">Is there / should there be a centralized place to put this path mapping logic? Right now, it seems there's a few different places it could go, but polluting the codebase in many different places seems far from ideal. Naturally I reached for the ClangdLSPServer::MessagesHandler, but in its current implementation it seems to mostly operate on JSON Values, and even then some replies bypass the MessagesHandler (e.g. publishDiagnostics/onFileUpdated)</span></p></li></ol><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap">Happy to hear any feedback!</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap">Thanks for taking the time,</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-variant-numeric:normal;font-variant-east-asian:normal;vertical-align:baseline;white-space:pre-wrap">William</span></p></span><br class="m_8031547381901639146gmail-Apple-interchange-newline"></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Jan 16, 2019 at 8:55 AM Ilya Biryukov <<a href="mailto:ibiryukov@google.com" target="_blank" rel="noreferrer">ibiryukov@google.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">The idea that I was playing around with was remapping the paths between network mount and a Clangd running on the remote machine.<div>I actually wrote an LSP wrapper that would update all the paths used along the way. It worked, but using it was a terrible pain. (Offtopic: network mounts are a terrible idea, rsyncing the code gives a so much better latency!)</div><div><br></div><div>As ugly as this sounds, I actually think that having an option in clangd to remap the paths is the preferred option here. It's feels like the only way that has a reasonable UX.</div><div>Just to make it clear, your setup is as follows:</div><div>- A development environment (where you run the builds, etc) is configured inside a docker image.</div><div>- The source code lives inside a folder on a host OS.</div><div>- The source code folder is mounted into the docker container.</div><div>- The editors run in the host OS, the language server runs inside the docker container.<br><div><br></div></div></div><br><div class="gmail_quote"><div dir="ltr">On Thu, Jan 10, 2019 at 6:01 PM Sam McCall <<a href="mailto:sammccall@google.com" target="_blank" rel="noreferrer">sammccall@google.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Hi William,<div><br></div><div>This is an idea Ilya did some thinking about before. The motivation was slightly different (editor on laptop, clangd on remote workstation) but I believe equivalent. </div><div>We're not going to get around needing to have all sources on both machines (or mounted from one to the other). Clangd and the editor both need to see them. So I think the path translation is indeed the bit to attack. The scary thing about adding file mapping is doing it consistently everywhere without making mistakes or adding lots of noise to the code.</div><div><br></div><div>An idea I want to throw out there: clangd performs reads via a VFS. This is an existing abstraction where path translation could be added without any additional complexity to clangd proper. </div><div>The way this would work: we give clangd a different view of the world and connect it directly to the editor (on the host). This means clangd needs to speak the host's language, so the VFS needs to simulate the FS layout of the host.</div><div>This leads to the main limitation: we need a compilation database that's consistent with the *host's* file layout. I suspect mechanically transforming compilation databases is hard (relative paths etc), so this may mean running the build system on the host (at least sufficiently to generate the CDB).</div><div>Not sure if there's a way to modify this idea to avoid the limitation.</div><div><br></div><div>I'm interested in how else we can get clangd to expose a different view of the world than its VFS sees in a consistent way, too!</div></div><br><div class="gmail_quote"><div dir="ltr">On Thu, Jan 10, 2019 at 9:12 AM William Wagner via clangd-dev <<a href="mailto:clangd-dev@lists.llvm.org" target="_blank" rel="noreferrer">clangd-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px;font-size:0.8125rem" dir="auto"><span style="font-size:0.8125rem">Hello,</span><br></div><br style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><div style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px;font-size:0.8125rem" dir="auto">I’ve been using clangd for developing a C++ project at work. Our development setup requires that we build and run our code inside a docker container. From a language server perspective this presents a few challenges:</div><br style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><ol style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><li style="list-style-type:decimal"><div style="font-size:0.8125rem">Communicating with the language server running in the container</div></li><li style="list-style-type:decimal"><div style="font-size:0.8125rem">Synchronizing the files between the host and the container</div></li><li style="list-style-type:decimal"><div style="font-size:0.8125rem">Translating file paths between the host lsp client  and docker lsp server</div></li><li style="list-style-type:decimal"><div style="font-size:0.8125rem">Having dependency files that are only in the container available to view on the host (for textDocument/definition on dependencies installed only in the container)</div></li></ol><br style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><div style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px;font-size:0.8125rem" dir="auto">Fortunately, docker’s facilities make 1) and 2) pretty easy to deal with. </div><br style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><div style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px;font-size:0.8125rem" dir="auto">1) can be solved by creating a bash script that contains something similar to:</div><div style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px;font-size:0.8125rem" dir="auto"> `docker exec -i <build_container> /path/to/clangd ${@:1}`</div><div style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px;font-size:0.8125rem" dir="auto">and pointing clangd.path to this script</div><br style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><div style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px;font-size:0.8125rem" dir="auto">2) can be solved by using a docker bind mount, which maps the directory of the project you’re working on into the container</div><br style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><div style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px;font-size:0.8125rem" dir="auto">3) can be solved by mounting the host:/path/to/project to an identical path in the container. Then there doesn't have to be any translation between the requests/responses between the file uris that the client and server send back and forth. However, this may not always be possible and still leaves the problem of external dependency paths.</div><br style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><div style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px;font-size:0.8125rem" dir="auto">4) has no easy solution yet afaik. A potentially simple one would be to copy just the dependency headers from the container over to some directory on the host, and be able to translate clangd response file uris to the appropriate path on the host. The way I envision that is an extra arg to the clangd server that supports path substitution, such as:</div><br style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><div style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px;font-size:0.8125rem" dir="auto">`clangd -path-mappings=’/host/home/project/deps:/container/deps;/host/home/project/:container/project`</div><br style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><div style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px;font-size:0.8125rem" dir="auto">So if I “Go To Definition” on an external symbol e.g. Foo, which is defined in /container/deps/foo.hh”, and I have the foo.hh header in /host/home/project/.deps/foo.hh, then the response from the servers textDocument/definition would substitute the /container/deps/foo.hh → /host/home/project/.deps/foo.hh and all would be well. </div><br style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><div style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px;font-size:0.8125rem" dir="auto">I believe sourcegraph has implemented an extension to the LSP to handle missing files on the client/server, but I cannot find the proposed spec. Also these are some github discussions that touch on the topics above:</div><ul style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><li style="list-style-type:disc"><div style="font-size:0.8125rem">Ccls supports a path Mappings config option that allows substitution, see <a href="https://github.com/MaskRay/ccls/issues/75" target="_blank" rel="noreferrer"><span style="font-size:0.8125rem">https://github.com/MaskRay/ccls/issues/75</span></a></div></li><li style="list-style-type:disc"><div style="font-size:0.8125rem">Discussion on remote langauge server proposal <span style="font-size:0.8125rem"><a href="https://github.com/Microsoft/language-server-protocol/issues/528" target="_blank" rel="noreferrer">https://github.com/Microsoft/language-server-protocol/issues/528</a></span></div></li></ul><br style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><div style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px;font-size:0.8125rem" dir="auto">I’d be happy to implement this path mapping functionality, but thought it’d be prudent to see what everyone else thinks before doing so.</div><br style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><div style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px;font-size:0.8125rem" dir="auto">Thanks!</div><br style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px"><br style="color:rgb(49,49,49);font-family:Arial,"BB.Proportional";white-space:pre-wrap;word-spacing:1px">
_______________________________________________<br>
clangd-dev mailing list<br>
<a href="mailto:clangd-dev@lists.llvm.org" target="_blank" rel="noreferrer">clangd-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/clangd-dev" rel="noreferrer noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/clangd-dev</a><br>
</blockquote></div>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="m_8031547381901639146gmail-m_-7561942117948804772gmail_signature"><div dir="ltr"><div><div dir="ltr"><div>Regards,</div><div>Ilya Biryukov</div></div></div></div></div>
</blockquote></div></div>
</blockquote></div>