Skip to content

Commit

Permalink
Improve location of external tools (#91)
Browse files Browse the repository at this point in the history
* Extract intrisinc list into its own file

* Add type attributes completion gif

* Add a basic language server implementation

* Update the minum supported version of vscode to 1.22.0

* Update changelog

* Locate bin tools by path

* Improve bin tools lookup

* Add command for install the fortran lang server
  • Loading branch information
krvajal authored Oct 14, 2018
1 parent 02e24e1 commit db6d1e3
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 14 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added

- Autoindentation rules for code blocks (thx @graceyangfan for the feature request)
- Auto indentation rules for code blocks (thx @graceyangfan for the feature request)

### Fixed

Expand All @@ -81,7 +81,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Fixed

- A bug in the regex to parse output errors from gfortran
- A bug in the regex to parse output errors from `gfortran`
- Now the spawn command uses the directory of the file `gfortran` is analyzing

## [0.5.1] - 2017-07-06
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,17 @@ This is a list of some of the snippets included, if you like to include addition

To trigger code validations you must save the file first.

## Fortran Language Server (Experimental)

This extension uses a host of tools to provide the various language features. An alternative is to use a single language server that provides the same feature.

Set `fortran.useLanguageServer` to `true` to use the Fortran language server from [Chris Hansen](https://github.com/hansec/fortran-language-server) for features like Hover, Definition, Find All References, Signature Help, Go to Symbol in File and Workspace.

- This is an experimental feature and is not available in Windows yet.
- Since only a single language server is spun up for given VS Code instance, having multi-root setup does not work
- If set to true, you will be prompted to install the Fortran language server. Once installed, you will have to reload VS Code window. The language server will then be run by the Fortran extension in the background to provide services needed for the above mentioned features.
- Every time you change the value of the setting `fortran.useLanguageServer`, you need to reload the VS Code window for it to take effect.

## Requirements

For the linter to work you need to have `gfortran` on your path, or wherever you configure it to be.
Expand Down
12 changes: 7 additions & 5 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import FortranLintingProvider from './features/linter-provider'
import FortranHoverProvider from './features/hover-provider'
import { FortranCompletionProvider } from './features/completion-provider'
import { FortranDocumentSymbolProvider } from './features/document-symbol-provider'
import { FORTRAN_FREE_FORM_ID } from './lib/helper'
import { FortranLangServer } from './lang-server'
import { ConfigurationFeature } from 'vscode-languageclient/lib/configuration'

import { FORTRAN_FREE_FORM_ID, EXTENSION_ID } from './lib/helper'
import { FortranLangServer, checkForLangServer } from './lang-server'


export function activate(context: vscode.ExtensionContext) {
let hoverProvider = new FortranHoverProvider()
let completionProvider = new FortranCompletionProvider()
let symbolProvider = new FortranDocumentSymbolProvider()

const extensionConfig = vscode.workspace.getConfiguration('LANGUAGE_ID')
const extensionConfig = vscode.workspace.getConfiguration(EXTENSION_ID)

if (extensionConfig.get('linterEnabled', true)) {
let linter = new FortranLintingProvider()
Expand All @@ -33,7 +33,9 @@ export function activate(context: vscode.ExtensionContext) {
FORTRAN_FREE_FORM_ID,
symbolProvider
)
if (extensionConfig.get('useLanguageServer')) {

if (checkForLangServer(extensionConfig)) {

const langServer = new FortranLangServer(context, extensionConfig)
langServer.start()
langServer.onReady().then(() => {
Expand Down
33 changes: 29 additions & 4 deletions src/lang-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,22 @@ import {
LanguageClientOptions,
Executable,
} from 'vscode-languageclient'
import { getBinPath, FORTRAN_FREE_FORM_ID } from './lib/helper'
import * as vscode from 'vscode'
import {
getBinPath,
FORTRAN_FREE_FORM_ID,
promptForMissingTool,
} from './lib/helper'
import { LANG_SERVER_TOOL_ID } from './lib/tools'

export class FortranLangServer {

class FortranLangServer {
c: LanguageClient
constructor(context, config) {
let langServerFlags: string[] = config.get('languageServerFlags', [])

const serverOptions: Executable = {
command: getBinPath('fortran-langserver'),
command: getBinPath(LANG_SERVER_TOOL_ID),
args: [...langServerFlags],
options: {},
}
Expand Down Expand Up @@ -42,4 +49,22 @@ class FortranLangServer {
}
}

export { FortranLangServer }
export function checkForLangServer(config) {
const useLangServer = config.get('useLanguageServer')
if (!useLangServer) return false
if (process.platform === 'win32') {
vscode.window.showInformationMessage(
'The Fortran language server is not supported on Windows yet.'
)
return false
}
let langServerAvailable = getBinPath('fortran-langserver')
if (!langServerAvailable) {
promptForMissingTool(LANG_SERVER_TOOL_ID)
vscode.window.showInformationMessage(
'Reload VS Code window after installing the Fortran language server'
)
}
return true
}

19 changes: 16 additions & 3 deletions src/lib/helper.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as fs from 'fs'
import * as vscode from 'vscode'
import intrinsics from './fortran-intrinsics'
import { installTool } from './tools'

// IMPORTANT: this should match the value
// on the package.json otherwise the extension won't
Expand All @@ -10,7 +11,6 @@ export const FORTRAN_FREE_FORM_ID = { language: LANGUAGE_ID, scheme: 'file' }
export { intrinsics }
export const EXTENSION_ID = 'fortran'


export const FORTRAN_KEYWORDS = [
'FUNCTION',
'MODULE',
Expand Down Expand Up @@ -118,6 +118,19 @@ let saveKeywordToJson = keyword => {
})
}

export function getBinPath(tool: string): string {
return '/usr/local/bin/fortls'
export { default as getBinPath } from './paths'

export function promptForMissingTool(tool: string) {
const items = ['Install']
let message = ''
if (tool === 'fortran-langserver') {
message =
'You choose to use the fortranLanguageServer functionality but it is not installed. Please press the Install button to install it'
}
vscode.window.showInformationMessage(message, ...items).then(selected => {
if (selected === 'Install') {
installTool(tool)
}
})

}
40 changes: 40 additions & 0 deletions src/lib/paths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as fs from 'fs'
import * as path from 'path'
import { toolBinNames } from './tools'

let binPathCache: { [tool: string]: string } = {}

export const envPath =
process.env['PATH'] ||
(process.platform === 'win32' ? process.env['Path'] : null)

// checks in the PATH defined in the PATH env variables
// for the specified tools and returns its complete path
export default function getBinPath(tool: string): string | null {
if (binPathCache[tool]) return binPathCache[tool]
const binDirPaths = envPath.split(path.delimiter)
const binName = getBinName(tool)
const possiblePaths = binDirPaths.map(binDirPath =>
path.join(binDirPath, binName)
)
for (let p of possiblePaths) {
if (fileExists(p)) {
// save in cache
binPathCache[tool] = p
return p
}
}
return null
}

function getBinName(tool: string): string {
return toolBinNames[tool]
}

function fileExists(filePath: string): boolean {
try {
return fs.statSync(filePath).isFile()
} catch (e) {
return false
}
}
23 changes: 23 additions & 0 deletions src/lib/tools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export const LANG_SERVER_TOOL_ID = 'fortran-langserver'
import * as cp from 'child_process'
export const toolBinNames = {
[LANG_SERVER_TOOL_ID]: 'fortls',
'gnu-compiler': 'gfortran',
}

export function installTool(toolname) {
if (toolname === LANG_SERVER_TOOL_ID) {
const installProcess = cp.spawn(
'pip',
'install fortran-language-server'.split(' ')
)
installProcess.on('exit', (code, signal) => {
if (code !== 0) {
// extension failed to install
}
})
installProcess.on('error', err => {
//failed to install
})
}
}

0 comments on commit db6d1e3

Please sign in to comment.