<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML lang="en">
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
<link href="style.css" rel="stylesheet" type="text/css">
<title>Guide: Using NppExec to compile sources with associated compilers</title>
<script src="show_matches.js" type="text/javascript"></script>
</HEAD>
<BODY>
<h3>Guide: Using NppExec to compile sources with associated compilers</h3>


<p>As a Notepad++ user, did you ever think about ability to compile your source
file with its associated compiler in a single action?</p>
<p>You may use the NppExec plugin to perform certain actions on your files, but
what about the automatization? What if you want your .c files to be compiled
with tcc, .cpp files to be compiled with g++ and .awk files to be interpretted
with gawk automatically, without explicit call to required compiler or
interpreter? Is it possible?</p>
<p>Yes, NppExec <u>already</u> allows you to do this. All you need is some imagination
and several things to do. And I'm about to tell what is needed.</p>

<br>

<p>Let's begin with several theoretical questions.</p>
<p>At first, how can NppExec understand which compiler/interpreter is required
by your current source file? NppExec is not a compiler, it does not have
any information about your file and does not know what to do with it.</p>
<p>Moreover, Notepad++ itself is not such IDE as Visual Studio or Dev-C++,
it does not include any compiler and also does not know what to do with your
source file.</p>
<p>So, the only way to compile your source file with required compiler is to tell
Notepad++ (to tell NppExec in our case) <u>which</u> compiler to use and <u>how</u> to
use it.</p>
<p>This is the solution which you may use already - explicit usage of certain
compiler/interpreter with certain source file. For example, you may want to
compile and run your .c source file with tcc (Tiny C Compiler). A simple NppExec's script can
be created for this purpose:</p>

<blockquote>
  <pre>&quot;C:\tools\tcc\tcc.exe&quot; -run &quot;$(FULL_CURRENT_PATH)&quot;</pre>
</blockquote>

<p>The full path &quot;C:\tools\tcc\tcc.exe&quot; specifies a path to required compiler;
Notepad++'es environment variable &quot;$(FULL_CURRENT_PATH)&quot; specifies full path
name to your current source file; and &quot;-run&quot; in tcc's command line means
&quot;run compiled source&quot;. The full path was given in quotes, because, in general,
it can contain spaces.</p>
<p>Now, we are talking about NppExec's script. This assumes the script has been
created and saved with some name which identified that script. If you are
not sure about NppExec's script creation &amp; saving, let me guide you.</p>

<br>

<p>To create &amp; save some NppExec's script, do the following:</p>
<p>1) Open the &quot;Execute NppExec Script...&quot; window: press the hotkey (F6) or
   select (main menu) Plugins -&gt; NppExec -&gt; Execute NppExec Script...</p>
<p>2) Type the text of your script in the &quot;Execute NppExec Script...&quot; window.
   For example:</p>

<blockquote>
  <pre>&quot;C:\tools\tcc\tcc.exe&quot; -run &quot;$(FULL_CURRENT_PATH)&quot;</pre>
</blockquote>

<p>3) Save this new script: press the &quot;Save...&quot; button, type your script name
   (for example, type &quot;run@.c&quot;) and press Save.</p>

<br>

<p>Now you can compile &amp; run any single .c file opened in Notepad++. To do it,
press F6 (default hotkey for the &quot;Execute NppExec Script...&quot; window), select
&quot;run@.c&quot; in the combo-box and press OK.</p>
<p>You can press Ctrl+F6 (by default) to execute the same script again without
showing the &quot;Execute NppExec Script...&quot; window.</p>

<br>

<p>As you can see, currently you have to call the &quot;run@.c&quot; script explicitly
in order to compile &amp; run your .c source file. Thus, to compile &amp; run
another source file (.cpp, .asm, .php, .lua, ...) you also have to call
corresponding script explicitly. [The last sentence assumes you have created
separate scripts for every language you use (.cpp, .asm, .php, .lua, ...)].</p>
<p>However, we don't want to call required script explicitly. We want NppExec
to call the &quot;run@.c&quot; script for a .c file and call different script required
for different (.cpp, .asm, .php, .lua, ...) file automatically.</p>
<p>So, a question: how can we do it?</p>
<p>The first part of the answer is in your source file's extension. There is
such environment varible as $(EXT_PART) which contains the extension of
current file opened in Notepad++.</p>
<p>The second part of the answer is in NppExec's internal command NPP_EXEC.
As you probably know already, this command expects an existing script name
or a script file name as its first argument. The purpose of this command is
to execute specified NppExec's script.</p>
<p>Thus, if you use NPP_EXEC command, and its first argument (a script to be
executed) depends on current file's extension, you can call different scripts
for different file types from one starting script!</p>
<p>Let's examine it in more detail.</p>

<br>

<p>We are about to create a general NppExec's script which would allow us to
call different scripts for different source files depending on their extension.
In other words, we use the NPP_EXEC command to call required script, and the
script name depends on current file's extension.</p>
<p>The name of the script above,
&quot;run@.c&quot;, consists of two parts: the prefix &quot;run@&quot; and the extension &quot;.c&quot;.</p>
<p>As the file's extension can be got from Notepad++, we can write general form
of this script's name: &quot;run@$(EXT_PART)&quot;.</p>
<p>It's not hard to understand that this script's name transforms to &quot;run@.cpp&quot;
for .cpp source file, &quot;run@.lua&quot; for .lua source file and so on.</p>
<p>So, let's create our general compile-or-run script which will be called each
time you want to compile or run <u>any</u> source file:</p>

<blockquote>
  <pre>// save current file
NPP_SAVE
// construct the script name to be called
SET Compiler = run@$(EXT_PART)
// enable the built-in error highlight filter locally
NPE_CONSOLE local -- x+
// call the script
NPP_EXEC &quot;$(Compiler)&quot;</pre>
</blockquote>

<p>Save this script as &quot;compile_or_run&quot;. Now this is your only starting script
which will allow you to compile or run <u>any</u> source file. I.e. press F6, select
the &quot;compile_or_run&quot; and press OK in order to compile or run <u>any</u> source file.</p>
<p>However, don't forget that this script requires existing scripts for every
source file you want to compile. Thus, &quot;run@.cpp&quot; must exist to compile a .cpp
file, &quot;run@.php&quot; must exist to compile a .php file and so on.</p>
<p>You can see several examples of such scripts below:</p>

<blockquote>
  <pre>// run@.c
&quot;C:\tools\tcc\tcc.exe&quot; -run &quot;$(FULL_CURRENT_PATH)&quot;

// run@.cpp
SET local g++ = C:\Dev-Cpp\bin\g++.exe
SET local obj = $(CURRENT_DIRECTORY)\$(NAME_PART)
&quot;$(g++)&quot; -c &quot;$(FULL_CURRENT_PATH)&quot; -o &quot;$(obj).o&quot;
&quot;$(g++)&quot; &quot;$(obj).o&quot; -o &quot;$(obj).exe&quot;
NPP_RUN &quot;$(obj).exe&quot;

// run@.awk
&quot;C:\tools\gawk\gawk.exe&quot; -f &quot;$(FULL_CURRENT_PATH)&quot;</pre>
</blockquote>

<p>All of these scripts will be started automatically from the &quot;compile_or_run&quot;
script for .c, .cpp and .awk files. You can create more &quot;run@...&quot; scripts to
support any source file extension you use.</p>

<br>

<p>Now, let's return to our &quot;compile_or_run&quot; script. It uses the NPP_EXEC command
which supports a script file name as its first argument. What does it mean?</p>
<p>It means you can execute NppExec's script from a file.</p>
<p>As you can see, current implementation of the &quot;compile_or_run&quot; script requires
a lot of additional &quot;run@...&quot; scripts to exist together with other scripts
which you may want to call explicitly. In the same time, you do not call the
&quot;run@...&quot; scripts explicitly. So, the &quot;run@...&quot; scripts may be undesired in
the NppExec's script combo-box (in the &quot;Execute NppExec Script...&quot; window).</p>
<p>Thus, you may modify the &quot;compile_or_run&quot; script in order to call script files
instead of internal scripts. For example:</p>

<blockquote>
  <pre>// compile_or_run
NPP_SAVE
SET Compiler = C:\tools\NppExec Scripts\run@$(EXT_PART).txt
NPE_CONSOLE local -- x+
NPP_EXEC &quot;$(Compiler)&quot;</pre>
</blockquote>

<p>Now you need to create a directory &quot;C:\tools\NppExec Scripts&quot; which will contain
the following files: &quot;run@.c.txt&quot;, &quot;run@.cpp.txt&quot;, &quot;run@.awk.txt&quot;and so on.</p>
<p>The text of these files will be exactly the same as in the scripts &quot;run@.c&quot;,
&quot;run@.cpp&quot; and &quot;run@.awk&quot; above.</p>
<p>E.g. the file &quot;C:\tools\NppExec Scripts\run@.awk.txt&quot; must contain</p>

<blockquote>
  <pre>&quot;C:\tools\gawk\gawk.exe&quot; -f &quot;$(FULL_CURRENT_PATH)&quot;</pre>
</blockquote>

<p>and so on for other file extensions (.c, .cpp, ...).</p>
<p>Similarly, the path to your NppExec Scripts can be relative to Notepad++.</p>
<p>For example:</p>

<blockquote>
  <pre>// compile_or_run
NPP_SAVE
SET Compiler = $(NPP_DIRECTORY)\NppExec Scripts\run@$(EXT_PART).txt
NPE_CONSOLE local -- x+
NPP_EXEC &quot;$(Compiler)&quot;</pre>
</blockquote>

<p>or</p>

<blockquote>
  <pre>// compile_or_run
NPP_SAVE
SET Compiler = $(PLUGINS_CONFIG_DIR)\NppExec Scripts\run@$(EXT_PART).txt
NPE_CONSOLE local -- x+
NPP_EXEC &quot;$(Compiler)&quot;</pre>
</blockquote>

<p>Such approach allows to use external text files as the NppExec Scripts, while
they are always available since they reside in Notepad++'s folder.</p>
<p>To read more information about the NPP_EXEC command, open the NppExec's
Console in Notepad++, and type:</p>

<blockquote>
  <pre>help npp_exec</pre>
</blockquote>

<p>and press Enter.</p>
<p>To read more information about the NPE_CONSOLE command, type:</p>

<blockquote>
  <pre>help npe_console</pre>
</blockquote>

<p>and press Enter.</p>
<p>To get general NppExec's help information, type just</p>

<blockquote>
  <pre>help</pre>
</blockquote>

<p>and press Enter.</p>

<br>

<p>You may have noticed, that the script &quot;compile_or_run&quot; uses a non-local
variable $(Compiler), such as:</p>

<blockquote>
  <pre>SET Compiler = run@$(EXT_PART)</pre>
</blockquote>

<p>Though, in general, it is recommended to use a local variable, e.g.</p>

<blockquote>
  <pre>SET local Compiler = run@$(EXT_PART)</pre>
</blockquote>

<p>Local variables, unlike non-local ones, are automatically deleted at the end
of the script where they were created. (So you don't have to use the UNSET
command for local variables at the end of your script.)</p>
<p>So, why the variable $(Compiler) is not a local one?</p>
<p>Consider a situation when the &quot;run@...&quot; script does not do what you expected
it to. In such case, you probably want to examine this script and correct it,
right? And here is when the existing variable $(Compiler) becomes useful! As
this variable holds the name of (or the path to) the just executed &quot;run@...&quot;
script, it's easy to see what exact &quot;run@...&quot; script needs to be examined.</p>
<p>Just type one the following in NppExec's Console:</p>

<blockquote>
  <pre>// to show the &quot;run@...&quot; script's name:
echo $(Compiler)

// to open the &quot;run@...&quot; script from a physical file:
NPP_OPEN $(Compiler)</pre>
</blockquote>

<br>

<p>Starting from NppExec v0.6 alpha 1, IF...ELSE IF...ELSE...ENDIF sequences are
supported in NppExec's scripts (see &quot;help if&quot;).</p>
<p>It means we can create a single NppExec's script that will deal with all the
file types we want.</p>
<p>For example:</p>

<blockquote>
  <pre>// setting internal messages off, error highlight filter on
NPE_CONSOLE local m- x+ --
// saving current file
NPP_SAVE
// file extension in lower case
set local ext ~ strlower $(EXT_PART)
// compiling/running...
if $(ext) == .c
  &quot;C:\tools\tcc\tcc.exe&quot; -run &quot;$(FULL_CURRENT_PATH)&quot;
else if $(ext) == .cpp
  env_set local PATH = $(path);C:\mingw32\bin;
  set local obj = $(CURRENT_DIRECTORY)\$(NAME_PART)
  cmd /C del &quot;$(obj).o&quot; 2&gt;nul &amp; del &quot;$(obj).exe&quot; 2&gt;nul
  echo Compiling...
  &quot;g++&quot; -c &quot;$(FULL_CURRENT_PATH)&quot;
  if $(EXITCODE) == 0
    &quot;g++&quot; &quot;$(obj).o&quot; -o &quot;$(obj).exe&quot;
    echo Running...
    NPP_RUN cmd /C if exist &quot;$(obj).exe&quot; &quot;$(obj).exe&quot; &amp;&amp; echo. &amp;&amp; pause
  endif
else if $(ext) == .awk
  &quot;C:\tools\gawk\gawk.exe&quot; -f &quot;$(FULL_CURRENT_PATH)&quot;
else
  messagebox &quot;Unknown file type!&quot;
endif</pre>
</blockquote>

<p>Such a single script includes everything in one place. On the one hand, it's nice to have everything in one place. On the other hand, it will create issues with maintenance and performance in the future.</p>
<p><i>Maintenance.</i> As time goes by, more and more file types (languages) will be added to this single script. The script will grow - and it will be harder and harder to find some exact things within the script. Moreover, if different parts of the script will share some common functionality (or, at least, some common variables) and you'll decide to make changes to the common functionality at some point, it will most likely lead to unexpected effects in different places. (For example, you may want some change to affect only certain languages, but in fact it will affect more of them). So, the bigger the script will become, the more accurate you'll need to be with each single change within the script.</p>
<p><i>Performance.</i> The bigger the script will become, the more time NppExec will need to process the entire script. The good thing is: NppExec's engine is internally fast enough to handle very big scripts without a noticeable delay. The bad thing is: NppExec's user interface (the NppExec Console) is very slow when there are a lot of messages to be printed. Here are the good news: it's easy to reduce the number of messages to be printed in NppExec's Console - and thus to enhance the overall performance. The presense of &quot;<i>NPE_CONSOLE local m-</i>&quot; in the beginning of the script already reduces the number of messages NppExec prints to its Console. Going further, you can explicitly specify when to disable and enable NppExec's output, thus having a complete manual control of when NppExec prints something to its Console and when it does not. Just notice that you'll need to update <em>each</em> IF-ELSE block to achieve that:</p>

<blockquote>
  <pre>// disabling any output to NppExec's Console
NPP_CONSOLE local -
// setting internal messages off, error highlight filter on
NPE_CONSOLE local m- x+ --
// saving current file
NPP_SAVE
// file extension in lower case
set local ext ~ strlower $(EXT_PART)
// compiling/running...
if $(ext) == .c
  NPP_CONSOLE local +  // enabling output to NppExec's Console
  &quot;C:\tools\tcc\tcc.exe&quot; -run &quot;$(FULL_CURRENT_PATH)&quot;
else if $(ext) == .cpp
  env_set local PATH = $(path);C:\mingw32\bin;
  set local obj = $(CURRENT_DIRECTORY)\$(NAME_PART)
  cmd /C del &quot;$(obj).o&quot; 2&gt;nul &amp; del &quot;$(obj).exe&quot; 2&gt;nul
  NPP_CONSOLE local +  // enabling output to NppExec's Console
  echo Compiling...
  &quot;g++&quot; -c &quot;$(FULL_CURRENT_PATH)&quot;
  if $(EXITCODE) == 0
    &quot;g++&quot; &quot;$(obj).o&quot; -o &quot;$(obj).exe&quot;
    echo Running...
    NPP_RUN cmd /C if exist &quot;$(obj).exe&quot; &quot;$(obj).exe&quot; &amp;&amp; echo. &amp;&amp; pause
  endif
else if $(ext) == .awk
  NPP_CONSOLE local +  // enabling output to NppExec's Console
  &quot;C:\tools\gawk\gawk.exe&quot; -f &quot;$(FULL_CURRENT_PATH)&quot;
else
  NPP_CONSOLE local +  // enabling output to NppExec's Console
  messagebox &quot;Unknown file type!&quot;
endif</pre>
</blockquote>

<br>

<p>One more thing regarding NppExec usage.</p>
<p>Compiler/interpreter's output is shown
in NppExec's Console and can be parsed by NppExec. It means that different
error/warning messages can be shown using different colours, and you can jump
to corresponding line in the source file by double-clicking such warning
or error message in the NppExec's Console.</p>
<p>To enable such parsing, you must tell NppExec what form do these error/warning
messages have (i.e. specify the message mask). You can configure it from
(main menu) Plugins -&gt; NppExec -&gt; Console Output Filters... -&gt; HighLight.</p>
<p>That window contains an example of parsing (highlighting) masks for GCC:</p>

<blockquote>
  <pre>Example 1: %ABSFILE%:%LINE%: warning:* =&gt; detects the warning lines from gcc
Example 2: %ABSFILE%:%LINE%: error:* =&gt; detects the error lines from gcc</pre>
</blockquote>

<p>I.e. to enable detection (parsing) of GCC errors in NppExec, you must specify
the mask of the compiler's error line (&quot;%ABSFILE%:%LINE%: error:*&quot;) and,
optionally, specify Red, Green and Blue components of the line to be
highlighted and, also optionally, this line can be shown using Italic, Bold
and/or Underlined font typeface. And, of course, corresponding check-box must
be checked to enable this parsing mask.</p>
<p>For example, if you want to see GCC's errors as Bold lines with Red colour
and GCC's warnings as Italic lines with Blue colour, it will look similar to
the following:</p>

<blockquote>
  <pre>[v] [%ABSFILE%:%LINE%: error:*       ]  0x80 0x00 0x00  [ ] [v] [ ]
[v] [%ABSFILE%:%LINE%: warning:*     ]  0x00 0x00 0x80  [v] [ ] [ ]</pre>
</blockquote>

<p>You can find some more notes and hints by typing</p>

<blockquote>
  <pre>help con_filter</pre>
</blockquote>

<br>

<p>Well, seems it's time to finish the guide.</p>
<p>I hope this guide was usefull for
you, because otherwise it was waste of time for both of us: the reader (you)
and the writer (me). Anyway, thank you for your time and for your interest!</p>
<p>If you like this guide, I hope it will inspire you to find your own usefull
application of NppExec's functions, and maybe to share it with us.</p>

<blockquote>
  <pre> </pre>
</blockquote>

</BODY>
</HTML>
