Repository: fwcd/kotlin-language-server
Issue: Resource hog and slow startup

The file-walk change made in this commit https://github.com/fwcd/kotlin-language-server/commit/adff2f93f43d6fd10635ad2a4d81226c4348c37b makes my fan go crazy and makes the server use several minues to start up. If I revert that commit it takes seconds, and no fan.

I'm testing on a small project on macOS with nvim-lsp. Have the same issue with coc.nvim on stable vim.

I might be able to look further on why, some other time.

Changed files:
shared/src/main/kotlin/org/javacs/kt/classpath/DefaultClassPathResolver.kt

diff --git a/shared/src/main/kotlin/org/javacs/kt/classpath/DefaultClassPathResolver.kt b/shared/src/main/kotlin/org/javacs/kt/classpath/DefaultClassPathResolver.kt
index a5bf531..b9e2a9a 100644
--- a/shared/src/main/kotlin/org/javacs/kt/classpath/DefaultClassPathResolver.kt
+++ b/shared/src/main/kotlin/org/javacs/kt/classpath/DefaultClassPathResolver.kt
@@ -3,7 +3,6 @@ package org.javacs.kt.classpath
 import org.javacs.kt.LOG
 import java.nio.file.Path
 import java.nio.file.PathMatcher
-import java.nio.file.Files
 import java.nio.file.FileSystems
 
 fun defaultClassPathResolver(workspaceRoots: Collection<Path>): ClassPathResolver =
@@ -14,7 +13,7 @@ fun defaultClassPathResolver(workspaceRoots: Collection<Path>): ClassPathResolve
 
 /** Searches the workspace for all files that could provide classpath info. */
 private fun workspaceResolvers(workspaceRoot: Path): Sequence<ClassPathResolver> {
-    val ignored: List<PathMatcher> = ignoredPathPatterns(workspaceRoot.resolve(".gitignore"))
+    val ignored: List<PathMatcher> = ignoredPathPatterns(workspaceRoot, workspaceRoot.resolve(".gitignore"))
     return folderResolvers(workspaceRoot, ignored).asSequence()
 }
 
@@ -22,29 +21,30 @@ private fun workspaceResolvers(workspaceRoot: Path): Sequence<ClassPathResolver>
 private fun folderResolvers(root: Path, ignored: List<PathMatcher>): Collection<ClassPathResolver> =
     root.toFile()
         .walk()
-        .onEnter { file -> ignored.none { it.matches(root.relativize(file.toPath())) } }
+        .onEnter { file -> ignored.none { it.matches(file.toPath()) } }
         .mapNotNull { asClassPathProvider(it.toPath()) }
         .toList()
 
 /** Tries to read glob patterns from a gitignore. */
-private fun ignoredPathPatterns(path: Path): List<PathMatcher> =
-    path.toFile()
+private fun ignoredPathPatterns(root: Path, gitignore: Path): List<PathMatcher> =
+    gitignore.toFile()
         .takeIf { it.exists() }
         ?.readLines()
         ?.map { it.trim() }
         ?.filter { it.isNotEmpty() && !it.startsWith("#") }
+        ?.map { it.removeSuffix("/") }
         ?.let { it + listOf(
             // Patterns that are ignored by default
             ".git"
         ) }
         ?.mapNotNull { try {
-            LOG.debug("Adding ignore pattern '{}' from {}", it, path)
-            FileSystems.getDefault().getPathMatcher("glob:$it")
+            LOG.debug("Adding ignore pattern '{}' from {}", it, gitignore)
+            FileSystems.getDefault().getPathMatcher("glob:$root**/$it")
         } catch (e: Exception) {
             LOG.warn("Did not recognize gitignore pattern: '{}' ({})", it, e.message)
             null
         } }
-        ?: emptyList<PathMatcher>()
+        ?: emptyList()
 
 /** Tries to create a classpath resolver from a file using as many sources as possible */
 private fun asClassPathProvider(path: Path): ClassPathResolver? =