Skip to content

Commit

Permalink
Merge pull request #6 from lydell/local-installs
Browse files Browse the repository at this point in the history
Support local installs of elm and elm-format
  • Loading branch information
ryan-haskell authored Jul 24, 2023
2 parents e2d2e19 + 91501a4 commit a5dc4a6
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 4 deletions.
9 changes: 7 additions & 2 deletions src/features/elm-format-on-save.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as vscode from "vscode"
import * as os from "os"
import * as child_process from "child_process"
import { Feature } from "./shared/logic"
import sharedLogic, { Feature } from "./shared/logic"

export const feature: Feature = ({ context }) => {
context.subscriptions.push(
Expand Down Expand Up @@ -38,7 +38,12 @@ function runElmFormat(document: vscode.TextDocument): Promise<string> {
const command = `elm-format --stdin --yes`
const original = document.getText()
return new Promise((resolve, reject) => {
const process_ = child_process.exec(command, async (err, stdout, stderr) => {
const process_ = child_process.exec(
command,
{
env: sharedLogic.npxEnv()
},
async (err, stdout, stderr) => {
if (err) {
const ELM_FORMAT_BINARY_NOT_FOUND = 127
if (err.code === ELM_FORMAT_BINARY_NOT_FOUND || err.message.includes(`'elm-format' is not recognized`)) {
Expand Down
7 changes: 6 additions & 1 deletion src/features/error-highlighting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,12 @@ const Elm = {
const command = `(cd ${input.elmJsonFile.projectFolder} && elm make ${deduplicated.join(' ')} --output=/dev/null --report=json)`
const promise: Promise<ParsedError | undefined> =
new Promise((resolve) =>
child_process.exec(command, async (err, _, stderr) => {
child_process.exec(
command,
{
env: sharedLogic.npxEnv()
},
async (err, _, stderr) => {
if (err) {
const ELM_BINARY_NOT_FOUND = 127
if (err.code === ELM_BINARY_NOT_FOUND || err.message.includes(`'elm' is not recognized`)) {
Expand Down
38 changes: 37 additions & 1 deletion src/features/shared/logic.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as path from 'path'
import * as vscode from 'vscode'
import * as AutodetectElmJson from './autodetect-elm-json'
import { ElmJsonFile, getDocumentationForElmPackage } from './elm-json-file'
Expand Down Expand Up @@ -99,6 +100,40 @@ const verifyFileExists = async (fsPath: string): Promise<string | undefined> =>
}
}

// Some people install elm and elm-format locally instead of globally, using
// npm or the elm-tooling CLI. To run locally installed tools, they use `npx`.
//
// `npx` adds all potential `node_modules/.bin` up the current directory to the
// beginning of PATH, for example:
//
// ❯ npx node -p 'process.env.PATH.split(path.delimiter)'
// [
// '/Users/you/stuff/node_modules/.bin',
// '/Users/you/node_modules/.bin',
// '/Users/node_modules/.bin',
// '/node_modules/.bin',
// '/usr/bin',
// 'etc'
// ]
//
// This function also does that, so that local installations just work.
function npxEnv() {
return {
...process.env,
PATH: [
...(vscode.workspace.workspaceFolders ?? [])
.flatMap(folder =>
folder.uri.fsPath.split(path.sep)
.map((_, index, parts) =>
[...parts.slice(0, index + 1), 'node_modules', '.bin'].join(path.sep)
)
.reverse()
),
process.env.PATH
].join(path.delimiter)
}
}

export default {
pluginId: 'elmLand',
findElmJsonFor,
Expand All @@ -107,5 +142,6 @@ export default {
findFirstOccurenceOfWordInFile: findFirstOccurrenceOfWordInFile,
isDefined,
doesModuleExposesValue,
keepFilesThatExist
keepFilesThatExist,
npxEnv
}

0 comments on commit a5dc4a6

Please sign in to comment.