profile
viewpoint
If you are wondering where the data of this site comes from, please visit https://api.github.com/users/lydell/events. GitMemory does not store any data, but only uses NGINX to cache data for a period of time. The idea behind GitMemory is simply to give users a better reading experience.
Simon Lydell lydell Insurello Stockholm Coder.

jashkenas/coffeescript 15959

Unfancy JavaScript

akhodakivskiy/VimFx 1371

Vim keyboard shortcuts for Firefox

elm-tooling/elm-tooling-cli 36

Manage Elm tools.

lydell/anishtro 11

anishtro is a layout for the letters of the English alphabet, made for symmetrical keyboards with at least one main key per thumb.

GeoffreyBooth/coffeescript 4

Unfancy JavaScript

lydell/autoprefixer-brunch 4

[DEPRECATED] Adds autoprefixer support to brunch.

lydell/blog 3

JavaScript, the web and other programming languages from a JavaScripter's perspective.

lydell/autoprefixer 2

Parse CSS and add vendor prefixes to rules by Can I Use

lydell/browser-tweaks 2

Personal browser extension containing a couple of tweaks.

GeoffreyBooth/prettier 0

Prettier is an opinionated code formatter.

pull request commentelm-tooling/elm-language-server

Remove the need for "entrypoints" in elm-tooling.json

Let's edit the readme and recommend elm-test-rs instead of elm-test? Do you see any problems with that?

I think that would make sense! We could mention that it’s for better performance, and then link to https://github.com/mpizenberg/elm-test-rs/#no-automatic-module-description so that people are aware of the difference in describe strings and that they might need to update them. What do you say, @mpizenberg?

Do we need to reword the setting for tests? Is it clear, that it can take any of the compatible test runner? Should we have two settings and pick what's available?

I don’t think two settings are needed. Either the user uses elm-test-rs or node-test-runner, but not both. If there were two settings we would need a third setting to choose between the two as well?

I think we can tweak the text to clarify that it’s the path to a test runner, not to elm-test/node-test-runner specifically. Maybe all we need is “The path to your elm-test <ins>or elm-test-rs</ins> exectuable.”

lydell

comment created time in 3 hours

pull request commentmpizenberg/elm-test-rs

Accept --output=/dev/null

This could potentially simplify the language server code a bit, but isn’t needed.

But people who switch from elm-test might appreciate this. Emacs users especially, according to https://github.com/rtfeldman/node-test-runner/issues/508.

mpizenberg

comment created time in 3 hours

push eventlydell/dotfiles

Simon Lydell

commit sha 8f64fc92af4896a608c889831f67be02f11ccdab

e: Base max columns on terminal width

view details

push time in 4 hours

issue commentmpizenberg/elm-test-rs

Json test return differs from elm-test

I guess the language server could easily support both, too.

razzeee

comment created time in 16 hours

issue commentmpizenberg/elm-test-rs

Json test return differs from elm-test

You could also include both properties to be able to ship without a breaking change?

razzeee

comment created time in 16 hours

Pull request review commentelm-tooling/elm-language-server

Remove the need for "entrypoints" in elm-tooling.json

 export class ElmMakeDiagnostics {   }    private async checkForErrors(-    workspaceRootPath: string,+    program: IProgram,     sourceFile: ISourceFile,   ): Promise<IElmIssue[]> {     const settings = await this.settings.getClientSettings(); -    const [relativePathsToFiles, message]: [NonEmptyArray<string>, string] =-      await this.elmToolingJsonManager.getEntrypoints(-        workspaceRootPath,-        sourceFile,-      );+    const workspaceRootPath = program.getRootPath().fsPath;++    const fileToRelativePath = (file: ISourceFile): string =>+      path.relative(workspaceRootPath, URI.parse(file.uri).fsPath);++    const sourceFilePath = fileToRelativePath(sourceFile);++    const treeMap = program.getForest().treeMap;++    const forestFiles: Array<ISourceFile> = Array.from(treeMap.values());++    const allFiles = forestFiles.some((file) => file.uri === sourceFile.uri)+      ? forestFiles+      : forestFiles.concat(sourceFile);++    const projectFiles = allFiles.filter((file) => !file.isDependency);++    const testFilesForSure = projectFiles.filter((file) => file.isTestFile);+    const otherFiles = projectFiles.filter((file) => !file.isTestFile);++    const entrypointsForSure = otherFiles.filter((file) => {+      switch (file.project.type) {+        case "application":+          return file.exposing?.has("main") ?? false; -    this.connection.console.info(-      `Find entrypoints: ${message}. See https://github.com/elm-tooling/elm-language-server#configuration for more information.`,+        case "package":+          return file.moduleName === undefined+            ? false+            : file.project.exposedModules.has(file.moduleName);+      }+    });++    const urisReferencedByEntrypoints = this.getUrisReferencedByEntrypoints(+      treeMap,+      entrypointsForSure,+    );++    const urisReferencedByTestsForSure = this.getUrisReferencedByEntrypoints(+      treeMap,+      testFilesForSure,+    );++    const allEntrypointsCoveredByTestsForSure = entrypointsForSure.every(+      (file) => urisReferencedByTestsForSure.has(file.uri),+    );++    // Files that aren’t imported from any entrypoint. These could be:+    //+    // - Tests inside `src/`.+    // - New files that aren’t imported by anything yet.+    // - Old leftover files that aren’t imported by anything.+    // - Files that _are_ used and aren’t tests but that still end up here+    //   because of:+    //   - The project doesn’t use `main =`, like `review/` for elm-review.+    //   - The user has accidentally remove `main =` or not exposed it.+    //+    // Since these _could_ be test, we compile them with `elm-test make` rather+    // than `elm make`, so that "test-dependencies" are allowed. If they _aren’t_+    // tests, the only downside of this is that if you accidentally import a+    // test-dependency, you won’t get an error for that. It should be an OK tradeoff.+    const possiblyTestFiles = otherFiles.filter(+      (file) => !urisReferencedByEntrypoints.has(file.uri),     ); -    const argsMake = [+    const argsElm = (files: Array<ISourceFile>): Array<string> => [       "make",-      ...relativePathsToFiles,+      ...files.map(fileToRelativePath),       "--report",       "json",       "--output",       "/dev/null",     ]; -    const argsTest = ["make", ...relativePathsToFiles, "--report", "json"];--    const makeCommand: string = settings.elmPath;-    const testCommand: string = settings.elmTestPath;-    const isTestFile = sourceFile.isTestFile;-    const args = isTestFile ? argsTest : argsMake;-    const testOrMakeCommand = isTestFile ? testCommand : makeCommand;-    const testOrMakeCommandWithOmittedSettings = isTestFile-      ? "elm-test"-      : "elm";-    const options = {-      cmdArguments: args,-      notFoundText: isTestFile-        ? "'elm-test' is not available. Install Elm via 'npm install -g elm-test'."-        : "The 'elm' compiler is not available. Install Elm via 'npm install -g elm'.",-    };+    const argsElmTest = (files: Array<ISourceFile>): Array<string> => [+      "make",+      ...files.map(fileToRelativePath),+      "--report",+      "json",+    ]; -    try {-      // Do nothing on success, but return that there were no errors-      utils.execCmdSync(-        testOrMakeCommand,-        testOrMakeCommandWithOmittedSettings,-        options,-        workspaceRootPath,-        this.connection,-      );-      return [];-    } catch (error) {+    const elmNotFound =+      "The 'elm' compiler is not available. Install via for example 'npm install -g elm'.";+    const elmTestNotFound =+      "'elm-test' (or 'elm-test-rs') is not available. Install via for example 'npm install -g elm-test'.";

Yeah it might be. English is not my native language. My thinking was:

  • We only have space to show one command?
  • Suggesting to install elm-test is not the only thing you can do – you can also install elm-test-rs.
  • Maybe we should suggest installing elm-test-rs, but there’s no simple command to do it.
  • There are more ways of installing Elm than via npm: The installer, brew, elm-tooling.
lydell

comment created time in 16 hours

PullRequestReviewEvent

Pull request review commentelm-tooling/elm-language-server

Remove the need for "entrypoints" in elm-tooling.json

 export function execCmdSync(     });   } catch (error) {     connection.console.warn(JSON.stringify(error));-    if (error.code && error.code === "ENOENT") {+    if (error.code === "ENOENT") {

All Node.js core errors have .code: https://nodejs.org/api/errors.html#errors_error_code_1 and https://nodejs.org/api/errors.html#errors_node_js_error_codes

But even if we caught some other error here, it doesn’t matter if .code is undefined. undefined === "ENOENT" returns false, so there’s no need for checking if the .code is truthy first.

lydell

comment created time in 16 hours

PullRequestReviewEvent

pull request commentelm-tooling/elm-language-server

Remove the need for "entrypoints" in elm-tooling.json

@mpizenberg Thanks for letting me know about that! It appears my testing with elm-test-rs was way too quick.

Yes, --report json is needed. This PR is broken as-is.

lydell

comment created time in a day

created tagelm-tooling/elm-tooling-cli

tagv1.6.0

Manage Elm tools.

created time in 2 days

delete branch elm-tooling/elm-tooling-cli

delete branch : bump

delete time in 2 days

push eventelm-tooling/elm-tooling-cli

Simon Lydell

commit sha 04a2f04025121baaaa74a26fb68326ee42d4ce14

elm-tooling-cli v1.6.0 (#73)

view details

push time in 2 days

PR opened elm-tooling/elm-tooling-cli

elm-tooling-cli v1.6.0
+6 -2

0 comment

3 changed files

pr created time in 2 days

create barnchelm-tooling/elm-tooling-cli

branch : bump

created branch time in 2 days

delete branch elm-tooling/elm-tooling-cli

delete branch : elm-test-rs-1.2.2

delete time in 2 days

push eventelm-tooling/elm-tooling-cli

Simon Lydell

commit sha d22d4d9b10883f744bb18462310c24adeb45e3ec

Add elm-test-rs 1.2.2 (#72)

view details

push time in 2 days

create barnchelm-tooling/elm-tooling-cli

branch : elm-test-rs-1.2.2

created branch time in 2 days

delete branch elm-tooling/elm-tooling-cli

delete branch : update-npm-packages

delete time in 2 days

push eventelm-tooling/elm-tooling-cli

Simon Lydell

commit sha 88d6e41ef01de4a8d4ad1ca871fbd032a5b4b3bd

Update npm packages (#71)

view details

push time in 2 days

create barnchelm-tooling/elm-tooling-cli

branch : update-npm-packages

created branch time in 2 days

pull request commentelm-tooling/elm-language-server

Remove the need for "entrypoints" in elm-tooling.json

I’ve tested this PR on the ~160k lines of Elm code at work.

  • It seems to work just fine!
  • We don’t have any tests inside src/, but we still get some files that are marked as “possibly tests” because we have some unused modules (which are ignored by elm-review).
  • I measured where time is spent in ElmMakeDiagnostics.checkForErrors. <10 ms is spent by the function itself, all the rest is just executing elm make and elm-test make/elm-test-rs make.
  • With elm-test-rs installed, running elm make plus elm-test-rs make in parallel takes ~150 ms.
  • With elm-test installed instead of elm-test-rs, elm make plus elm-test-rs make takes ~400 ms (because of Node.js startup time). So using elm-test-rs is a big win!

@razzeee If you think this approach looks good, let me know and I’ll go ahead and remove all elm-tooling.json/entrypoints related stuff. Or tell me if you’d rather have that in a separate PR.

lydell

comment created time in 2 days

pull request commentelm-tooling/elm-language-server

Remove the need for "entrypoints" in elm-tooling.json

@razzeee After some brainstorming on Slack we came up with a good algorithm. Implementing it felt good!

  • For packages, "test-dependencies" is allowed everywhere but in "exposed-modules", which should be a perfect solution.
  • For applications, we do our best:
    • Files with main = are entrypoints for sure. Any module referenced from an entry point cannot import "test-dependencies" (perfect).
    • Files in tests/ are tests for sure and can import "test-dependencies" (perfect).
    • Remaining files could be tests so they can import "test-dependencies" (tradeoff). This means that all Elm Make diagnostics should be correct (fully sound), but some errors for "test-dependencies" imports could be missing (not complete). That’s much better than <em>in</em>correct Elm Make diagnostics (not sound) but no missing (read: too many) "test-dependencies" imports errors ((over-)complete).

Bonus: We now support elm-test-rs, since it’s faster than elm-test (no Node.js 100-200 ms startup cost).

lydell

comment created time in 2 days

Pull request review commentelm-tooling/elm-language-server

Remove the need for "entrypoints" in elm-tooling.json

 import { URI } from "vscode-uri"; import { IElmPackageCache } from "../elmPackageCache"; import { IClientSettings } from "../../util/settings"; import { ElmProject } from "../program";+import { NonEmptyArray } from "../../util/utils";  export const isWindows = process.platform === "win32";  /** Options for execCmdSync */-export interface IExecCmdOptions {+export interface IExecCmdSyncOptions {   /** Any arguments */   cmdArguments?: string[];-  /** Shows a message if an error occurs (in particular the command not being */-  /* found), instead of rejecting. If this happens, the promise never resolves */-  showMessageOnError?: boolean;

This was unused

lydell

comment created time in 2 days

Pull request review commentelm-tooling/elm-language-server

Remove the need for "entrypoints" in elm-tooling.json

 export class ElmMakeDiagnostics {   }    private async checkForErrors(-    workspaceRootPath: string,+    program: IProgram,     sourceFile: ISourceFile,   ): Promise<IElmIssue[]> {     const settings = await this.settings.getClientSettings(); -    const [relativePathsToFiles, message]: [NonEmptyArray<string>, string] =-      await this.elmToolingJsonManager.getEntrypoints(-        workspaceRootPath,-        sourceFile,-      );+    const workspaceRootPath = program.getRootPath().fsPath;++    const fileToRelativePath = (file: ISourceFile): string =>+      path.relative(workspaceRootPath, URI.parse(file.uri).fsPath);++    const sourceFilePath = fileToRelativePath(sourceFile);++    const treeMap = program.getForest().treeMap;++    const forestFiles: Array<ISourceFile> = Array.from(treeMap.values());++    const allFiles = forestFiles.some((file) => file.uri === sourceFile.uri)+      ? forestFiles+      : forestFiles.concat(sourceFile);++    const projectFiles = allFiles.filter((file) => !file.isDependency);++    const testFilesForSure = projectFiles.filter((file) => file.isTestFile);+    const otherFiles = projectFiles.filter((file) => !file.isTestFile);++    const entrypointsForSure = otherFiles.filter((file) => {+      switch (file.project.type) {+        case "application":+          return file.exposing?.has("main") ?? false; -    this.connection.console.info(-      `Find entrypoints: ${message}. See https://github.com/elm-tooling/elm-language-server#configuration for more information.`,+        case "package":+          return file.moduleName === undefined+            ? false+            : file.project.exposedModules.has(file.moduleName);+      }+    });++    const urisReferencedByEntrypoints = this.getUrisReferencedByEntrypoints(+      treeMap,+      entrypointsForSure,+    );++    const urisReferencedByTestsForSure = this.getUrisReferencedByEntrypoints(+      treeMap,+      testFilesForSure,+    );++    const allEntrypointsCoveredByTestsForSure = entrypointsForSure.every(+      (file) => urisReferencedByTestsForSure.has(file.uri),+    );++    // Files that aren’t imported from any entrypoint. These could be:+    //+    // - Tests inside `src/`.+    // - New files that aren’t imported by anything yet.+    // - Old leftover files that aren’t imported by anything.+    // - Files that _are_ used and aren’t tests but that still end up here+    //   because of:+    //   - The project doesn’t use `main =`, like `review/` for elm-review.+    //   - The user has accidentally remove `main =` or not exposed it.+    //+    // Since these _could_ be test, we compile them with `elm-test make` rather+    // than `elm make`, so that "test-dependencies" are allowed. If they _aren’t_+    // tests, the only downside of this is that if you accidentally import a+    // test-dependency, you won’t get an error for that. It should be an OK tradeoff.+    const possiblyTestFiles = otherFiles.filter(+      (file) => !urisReferencedByEntrypoints.has(file.uri),     ); -    const argsMake = [+    const argsElm = (files: Array<ISourceFile>): Array<string> => [       "make",-      ...relativePathsToFiles,+      ...files.map(fileToRelativePath),       "--report",       "json",       "--output",       "/dev/null",     ]; -    const argsTest = ["make", ...relativePathsToFiles, "--report", "json"];--    const makeCommand: string = settings.elmPath;-    const testCommand: string = settings.elmTestPath;-    const isTestFile = sourceFile.isTestFile;-    const args = isTestFile ? argsTest : argsMake;-    const testOrMakeCommand = isTestFile ? testCommand : makeCommand;-    const testOrMakeCommandWithOmittedSettings = isTestFile-      ? "elm-test"-      : "elm";-    const options = {-      cmdArguments: args,-      notFoundText: isTestFile-        ? "'elm-test' is not available. Install Elm via 'npm install -g elm-test'."-        : "The 'elm' compiler is not available. Install Elm via 'npm install -g elm'.",-    };+    const argsElmTest = (files: Array<ISourceFile>): Array<string> => [+      "make",+      ...files.map(fileToRelativePath),+      "--report",+      "json",+    ]; -    try {-      // Do nothing on success, but return that there were no errors-      utils.execCmdSync(-        testOrMakeCommand,-        testOrMakeCommandWithOmittedSettings,-        options,-        workspaceRootPath,-        this.connection,-      );-      return [];-    } catch (error) {+    const elmNotFound =+      "The 'elm' compiler is not available. Install via for example 'npm install -g elm'.";+    const elmTestNotFound =+      "'elm-test' (or 'elm-test-rs') is not available. Install via for example 'npm install -g elm-test'.";++    // - If all entrypoints are covered by tests, we only need to run `elm-test make`.+    // - Otherwise, call `elm make` for all entrypoints (if any).+    // - Call `elm-test make` for all tests (if any), plus potential tests.+    // - If there’s no `tests/` folder but files that _could_ be tests, try to+    //   call `elm-test make` but fall back to `elm make` in case they’re not+    //   tests and the user hasn’t got elm-test installed.+    const results = await Promise.allSettled([

This is the compilation strategy.

Note that with this approach we try to call elm make with just the entrypoints again, which is slightly faster than calling it with all files.

lydell

comment created time in 2 days