mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-29 17:34:43 +00:00
Merge pull request #515 from gradha/pr_idetools_improvements
Idetools improvements
This commit is contained in:
153
doc/idetools.txt
153
doc/idetools.txt
@@ -11,13 +11,13 @@
|
||||
Nimrod differs from many other compilers in that it is really fast,
|
||||
and being so fast makes it suited to provide external queries for
|
||||
text editors about the source code being written. Through the
|
||||
``idetools`` command of `the compiler <nimrodc.html>`_, any IDE can
|
||||
query a ``.nim`` source file and obtain useful information like
|
||||
`idetools`:idx: command of `the compiler <nimrodc.html>`_, any IDE
|
||||
can query a ``.nim`` source file and obtain useful information like
|
||||
definition of symbols or suggestions for completion.
|
||||
|
||||
This document will guide you through the available options. If you
|
||||
want to look at practical examples of idetools support you can look
|
||||
at the test files found in ``tests/caas/*.txt`` or `various editor
|
||||
at the test files found in the `Test suite`_ or `various editor
|
||||
integrations <https://github.com/Araq/Nimrod/wiki/Editor-Support>`_
|
||||
already available.
|
||||
|
||||
@@ -119,7 +119,9 @@ separators!).
|
||||
|
||||
The typical usage scenario for this option is to call it after the
|
||||
user has typed the dot character for `the object oriented call
|
||||
syntax <tut2.html#method-call-syntax>`_.
|
||||
syntax <tut2.html#method-call-syntax>`_. Idetools will try to return
|
||||
the suggestions sorted first by scope (from innermost to outermost)
|
||||
and then by item name.
|
||||
|
||||
|
||||
Invokation context
|
||||
@@ -162,12 +164,12 @@ clicks it and after a second or two the IDE displays where that
|
||||
symbol is defined. Such latencies would be terrible for features
|
||||
like symbol suggestion, plus why wait at all if we can avoid it?
|
||||
|
||||
The idetools command can be run as a compiler service, where you
|
||||
first launch the compiler and it will stay online as a server,
|
||||
accepting queries in a telnet like fashion. The advantage of staying
|
||||
on is that for many queries the compiler can cache the results of
|
||||
the compilation, and subsequent queries should be fast in the
|
||||
millisecond range, thus being responsive enough for IDEs.
|
||||
The idetools command can be run as a compiler service (`caas`:idx:),
|
||||
where you first launch the compiler and it will stay online as a
|
||||
server, accepting queries in a telnet like fashion. The advantage
|
||||
of staying on is that for many queries the compiler can cache the
|
||||
results of the compilation, and subsequent queries should be fast
|
||||
in the millisecond range, thus being responsive enough for IDEs.
|
||||
|
||||
If you want to start the server using stdin/stdout as communication
|
||||
you need to type::
|
||||
@@ -188,7 +190,7 @@ of text it thinks necessary plus an empty line to indicate the end
|
||||
of the answer.
|
||||
|
||||
You can find examples of client/server communication in the idetools
|
||||
tests found in ``tests/caas/*.txt``.
|
||||
tests found in the `Test suite`_.
|
||||
|
||||
|
||||
Parsing idetools output
|
||||
@@ -293,6 +295,22 @@ posterior instances of the iterator.
|
||||
col 7: "iterates over any unicode character of the string `s`."
|
||||
|
||||
|
||||
skLabel
|
||||
-------
|
||||
|
||||
| **Third column**: module + [n scope nesting] + name.
|
||||
| **Fourth column**: always the empty string.
|
||||
| **Docstring**: always the empty string.
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc test(text: string) =
|
||||
var found = -1
|
||||
block loops:
|
||||
--> col 2: $MODULE.test.loops
|
||||
col 3: ""
|
||||
col 7: ""
|
||||
|
||||
|
||||
skLet
|
||||
-----
|
||||
|
||||
@@ -308,6 +326,26 @@ skLet
|
||||
col 7: ""
|
||||
|
||||
|
||||
skMacro
|
||||
-------
|
||||
|
||||
The fourth column will be the empty string if the macro is being
|
||||
defined, since at that point in the file the parser hasn't processed
|
||||
the full line yet. The signature will be returned complete in
|
||||
posterior instances of the macro.
|
||||
|
||||
| **Third column**: module + [n scope nesting] + macro name.
|
||||
| **Fourth column**: signature of the macro including return type.
|
||||
| **Docstring**: docstring if available.
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc testMacro() =
|
||||
expect(EArithmetic):
|
||||
--> col 2: idetools_api.expect
|
||||
col 3: proc (varargs[expr], stmt): stmt
|
||||
col 7: ""
|
||||
|
||||
|
||||
skMethod
|
||||
--------
|
||||
|
||||
@@ -465,3 +503,96 @@ skVar
|
||||
--> col 2: $MODULE.writeTempFile.output
|
||||
col 3: TFile
|
||||
col 7: ""
|
||||
|
||||
|
||||
Test suite
|
||||
==========
|
||||
|
||||
To verify that idetools is working properly there are files in the
|
||||
``tests/caas/`` directory which provide unit testing. If you find
|
||||
odd idetools behaviour and are able to reproduce it, you are welcome
|
||||
to report it as a bug and add a test to the suite to avoid future
|
||||
regressions.
|
||||
|
||||
|
||||
Running the test suite
|
||||
----------------------
|
||||
|
||||
At the moment idetools support is still in development so the test
|
||||
suite is not integrated with the main test suite and you have to
|
||||
run it manually. First you have to compile the tester::
|
||||
|
||||
$ cd my/nimrod/checkout
|
||||
$ nimrod c tests/tester.nim
|
||||
|
||||
Running the tester without parameters will display some options.
|
||||
To run the caas test suite (and other special tests) you need to
|
||||
use the `special` command. You need to run this command from the
|
||||
root of the checkout or it won't be able to open the required files::
|
||||
|
||||
$ ./tests/tester special
|
||||
|
||||
However this is a roundabout way of running the test suite. You can
|
||||
also compile and run ``tests/caasdriver.nim`` manually. In fact,
|
||||
running it manually will allow you to specify special parameters
|
||||
too. Example::
|
||||
|
||||
$ cd my/nimrod/checkout/tests
|
||||
$ nimrod c caasdriver.nim
|
||||
|
||||
Running the ``caasdriver`` without parameters will attempt to process
|
||||
all the test cases in all three operation modes. If a test succeeds
|
||||
nothing will be printed and the process will exit with zero. If any
|
||||
test fails, the specific line of the test preceeding the failure
|
||||
and the failure itself will be dumped to stdout, along with a final
|
||||
indicator of the success state and operation mode. You can pass the
|
||||
parameter ``verbose`` to force all output even on successfull tests.
|
||||
|
||||
The normal operation mode is called ``ProcRun`` and it involves
|
||||
starting a process for each command or query, similar to running
|
||||
manually the Nimrod compiler from the commandline. The ``CaasRun``
|
||||
mode starts a server process to answer all queries. The ``SymbolProcRun``
|
||||
mode is used by compiler developers. This means that running all
|
||||
tests involves processing all ``*.txt`` files three times, which
|
||||
can be quite time consuming.
|
||||
|
||||
If you don't want to run all the test case files you can pass any
|
||||
substring as a parameter to ``caasdriver``. Only files matching the
|
||||
passed substring will be run. The filtering doesn't use any globbing
|
||||
metacharacters, it's a plain match. For example, to run only
|
||||
``*-compile*.txt`` tests in verbose mode::
|
||||
|
||||
./caasdriver verbose -compile
|
||||
|
||||
|
||||
Test case file format
|
||||
---------------------
|
||||
|
||||
All the ``tests/caas/*.txt`` files encode a session with the compiler:
|
||||
|
||||
* The first line indicates the main project file.
|
||||
|
||||
* Lines starting with ``>`` indicate a command to be sent to the
|
||||
compiler and the lines following a command include checks for
|
||||
expected or forbidden output (``!`` for forbidden).
|
||||
|
||||
* If a line starts with ``#`` it will be ignored completely, so you
|
||||
can use that for comments.
|
||||
|
||||
* Since some cases are specific to either ``ProcRun`` or ``CaasRun``
|
||||
modes, you can prefix a line with the mode and the line will be
|
||||
processed only in that mode.
|
||||
|
||||
* The rest of the line is treated as a `regular expression <re.html>`_,
|
||||
so be careful escaping metacharacters like parenthesis.
|
||||
|
||||
Before the line is processed as a regular expression, some basic
|
||||
variables are searched for and replaced in the tests. The variables
|
||||
which will be replaced are:
|
||||
|
||||
* **$TESTNIM**: filename specified in the first line of the script.
|
||||
* **$MODULE**: like $TESTNIM but without extension, useful for
|
||||
expected output.
|
||||
|
||||
When adding a test case to the suite it is a good idea to write a
|
||||
few comments about what the test is meant to verify.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import unicode, sequtils
|
||||
import unicode, sequtils, macros, re
|
||||
|
||||
proc test_enums() =
|
||||
var o: Tfile
|
||||
@@ -41,3 +41,44 @@ proc newLit(x: int): PLiteral = PLiteral(x: x)
|
||||
proc newPlus(a, b: PExpr): PPlusExpr = PPlusExpr(a: a, b: b)
|
||||
|
||||
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
|
||||
|
||||
proc findVowelPosition(text: string) =
|
||||
var found = -1
|
||||
block loops:
|
||||
for i, letter in pairs(text):
|
||||
for j in ['a', 'e', 'i', 'o', 'u']:
|
||||
if letter == j:
|
||||
found = i
|
||||
break loops # leave both for-loops
|
||||
echo found
|
||||
|
||||
findVowelPosition("Zerg") # should output 1, position of vowel.
|
||||
|
||||
macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} =
|
||||
## Expect docstrings
|
||||
let exp = callsite()
|
||||
template expectBody(errorTypes, lineInfoLit: expr,
|
||||
body: stmt): PNimrodNode {.dirty.} =
|
||||
try:
|
||||
body
|
||||
assert false
|
||||
except errorTypes:
|
||||
nil
|
||||
|
||||
var body = exp[exp.len - 1]
|
||||
|
||||
var errorTypes = newNimNode(nnkBracket)
|
||||
for i in countup(1, exp.len - 2):
|
||||
errorTypes.add(exp[i])
|
||||
|
||||
result = getAst(expectBody(errorTypes, exp.lineinfo, body))
|
||||
|
||||
proc err =
|
||||
raise newException(EArithmetic, "some exception")
|
||||
|
||||
proc testMacro() =
|
||||
expect(EArithmetic):
|
||||
err()
|
||||
|
||||
testMacro()
|
||||
let notAModule = re"(\w+)=(.*)"
|
||||
|
||||
@@ -42,3 +42,18 @@ def\tskField\t$MODULE.TPerson.name\tbad_string\t
|
||||
|
||||
> idetools --track:$TESTNIM,43,7 --def $SILENT
|
||||
def\tskMethod\t$MODULE.eval\tproc \(PPlusExpr\): int\t
|
||||
|
||||
> idetools --track:$TESTNIM,47,8 --def $SILENT
|
||||
def\tskLabel\t$MODULE.findVowelPosition.loops\t\t
|
||||
# For some reason the use of the label with break displaces its position.
|
||||
> idetools --track:$TESTNIM,52,16 --def $SILENT
|
||||
def\tskLabel\t$MODULE.findVowelPosition.loops\t\t
|
||||
|
||||
# Displaced macro usage by one character.
|
||||
> idetools --track:$TESTNIM,80,2 --def $SILENT
|
||||
def\tskMacro\t$MODULE.expect\tproc \(varargs\[expr\], stmt\): stmt\t
|
||||
|
||||
# The syntax for extended raw string literals should not be returned as module
|
||||
# but as the proc re() inside the re module.
|
||||
> idetools --track:$TESTNIM,84,17 --def $SILENT
|
||||
!def\tskModule
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
main.nim
|
||||
# This example shows how the suggest feature can be used on a partial file
|
||||
# using the --trackDirty switch.
|
||||
> idetools --trackDirty:main_dirty.nim,$TESTNIM,12,7 --suggest $SILENT
|
||||
skField\tx
|
||||
skField\ty
|
||||
# Repeating the query in caas should work always and retrieve same output.
|
||||
CaasRun > idetools --trackDirty:main_dirty.nim,$TESTNIM,12,7 --suggest $SILENT
|
||||
CaasRun skField\tx
|
||||
CaasRun skField\ty
|
||||
> c --verbosity:0 --hints:on
|
||||
SuccessX
|
||||
|
||||
|
||||
26
tests/caas/suggest-invalid-source.txt
Normal file
26
tests/caas/suggest-invalid-source.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
main_dirty.nim
|
||||
# A variant of the suggest-compile.txt, instead of using a "base" correct
|
||||
# source, this one uses the "broken" main_dirty.nim which won't compile. The
|
||||
# test tries to stress idetools to still provide a valid answer if possible,
|
||||
# and at least provide the same output with repeated queries rather than dying
|
||||
# after the first compilation error.
|
||||
|
||||
# The first query should work and provide valid suggestions.
|
||||
> idetools --track:$TESTNIM,12,6 --suggest $SILENT
|
||||
skField\tx
|
||||
skField\ty
|
||||
|
||||
# Repeating the query should work too.
|
||||
> idetools --track:$TESTNIM,12,6 --suggest $SILENT
|
||||
skField\tx
|
||||
skField\ty
|
||||
|
||||
# Expect now a compilation failure.
|
||||
> c
|
||||
!SuccessX
|
||||
invalid indentation
|
||||
|
||||
# Repeating suggestions *after broken compilation* should work too.
|
||||
> idetools --track:$TESTNIM,12,6 --suggest $SILENT
|
||||
skField\tx
|
||||
skField\ty
|
||||
@@ -2,45 +2,7 @@ import osproc, streams, os, strutils, re
|
||||
|
||||
## Compiler as a service tester.
|
||||
##
|
||||
## This test cases uses the txt files in the caas/ subdirectory.
|
||||
##
|
||||
## Each of the text files inside encodes a session with the compiler:
|
||||
##
|
||||
## The first line indicates the main project file.
|
||||
##
|
||||
## Lines starting with '>' indicate a command to be sent to the compiler and
|
||||
## the lines following a command include checks for expected or forbidden
|
||||
## output (! for forbidden).
|
||||
##
|
||||
## If a line starts with '#' it will be ignored completely, so you can use that
|
||||
## for comments.
|
||||
##
|
||||
## All the tests are run both in ProcRun (each command creates a separate
|
||||
## process) and CaasRun (first command starts up a server and it is reused for
|
||||
## the rest) modes. Since some cases are specific to either ProcRun or CaasRun
|
||||
## modes, you can prefix a line with the mode and the line will be processed
|
||||
## only in that mode.
|
||||
##
|
||||
## The rest of the line is treated as a regular expression, so be careful
|
||||
## escaping metacharacters like parenthesis. Before the line is processed as a
|
||||
## regular expression, some basic variables are searched for and replaced in
|
||||
## the tests. The variables which will be replaced are:
|
||||
##
|
||||
## - $TESTNIM: filename specified in the first line of the script.
|
||||
## - $MODULE: like $TESTNIM but without extension, useful for expected output.
|
||||
##
|
||||
## You can optionally pass parameters at the command line to modify the
|
||||
## behaviour of the test suite. By default only tests which fail will be echoed
|
||||
## to stdout. If you want to see all the output pass the word "verbose" as a
|
||||
## parameter.
|
||||
##
|
||||
## If you don't want to run all the test case files, you can pass any substring
|
||||
## as a parameter. Only files matching the passed substring will be run. The
|
||||
## filtering doesn't use any globbing metacharacters, it's a plain match.
|
||||
##
|
||||
## Example to run only "*-compile*.txt" tests in verbose mode:
|
||||
##
|
||||
## ./caasdriver verbose -compile
|
||||
## Please read docs/idetools.txt for information about this.
|
||||
|
||||
|
||||
type
|
||||
@@ -84,6 +46,8 @@ proc startNimrodSession(project, script: string, mode: TRunMode):
|
||||
|
||||
if mode == SymbolProcRun:
|
||||
removeDir(nimcacheDir / result.nimcache)
|
||||
else:
|
||||
removeDir(nimcacheDir / "nimcache")
|
||||
|
||||
if mode == CaasRun:
|
||||
result.nim = startProcess(NimrodBin, workingDir = dir,
|
||||
|
||||
Reference in New Issue
Block a user