summary refs log tree commit diff stats
path: root/tools/niminst
diff options
context:
space:
mode:
authorClay Sweetser <clay.sweetser@gmail.com>2014-10-19 02:20:44 -0400
committerClay Sweetser <clay.sweetser@gmail.com>2014-10-19 02:20:44 -0400
commitcdd5b503b40f46d006913f52186bf91dee8ac965 (patch)
treeb208429de928a11cf439420f413b62aee968fd65 /tools/niminst
parentd73d752187ce108f0501810e1574f91533499ff4 (diff)
downloadNim-cdd5b503b40f46d006913f52186bf91dee8ac965.tar.gz
Update the NSIS Installer Script
Diffstat (limited to 'tools/niminst')
-rw-r--r--tools/niminst/EnvVarUpdate.nsh346
-rw-r--r--tools/niminst/nsis.tmpl415
2 files changed, 595 insertions, 166 deletions
diff --git a/tools/niminst/EnvVarUpdate.nsh b/tools/niminst/EnvVarUpdate.nsh
new file mode 100644
index 000000000..4340b8f3c
--- /dev/null
+++ b/tools/niminst/EnvVarUpdate.nsh
@@ -0,0 +1,346 @@
+/**
+ *  EnvVarUpdate.nsh
+ *    : Environmental Variables: append, prepend, and remove entries
+ *
+ *     WARNING: If you use StrFunc.nsh header then include it before this file
+ *              with all required definitions. This is to avoid conflicts
+ *
+ *  Usage:
+ *    ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString"
+ *
+ *  Credits:
+ *  Version 1.0 
+ *  * Cal Turney (turnec2)
+ *  * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this
+ *    function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar,
+ *    WriteEnvStr, and un.DeleteEnvStr
+ *  * Diego Pedroso (deguix) for StrTok
+ *  * Kevin English (kenglish_hi) for StrContains
+ *  * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry  
+ *    (dandaman32) for StrReplace
+ *
+ *  Version 1.1 (compatibility with StrFunc.nsh)
+ *  * techtonik
+ *
+ *  http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries
+ *
+ */
+
+
+!ifndef ENVVARUPDATE_FUNCTION
+!define ENVVARUPDATE_FUNCTION
+!verbose push
+!verbose 3
+!include "LogicLib.nsh"
+!include "WinMessages.NSH"
+!include "StrFunc.nsh"
+
+; ---- Fix for conflict if StrFunc.nsh is already includes in main file -----------------------
+!macro _IncludeStrFunction StrFuncName
+  !ifndef ${StrFuncName}_INCLUDED
+    ${${StrFuncName}}
+  !endif
+  !ifndef Un${StrFuncName}_INCLUDED
+    ${Un${StrFuncName}}
+  !endif
+  !define un.${StrFuncName} "${Un${StrFuncName}}"
+!macroend
+
+!insertmacro _IncludeStrFunction StrTok
+!insertmacro _IncludeStrFunction StrStr
+!insertmacro _IncludeStrFunction StrRep
+
+; ---------------------------------- Macro Definitions ----------------------------------------
+!macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
+  Push "${EnvVarName}"
+  Push "${Action}"
+  Push "${RegLoc}"
+  Push "${PathString}"
+    Call EnvVarUpdate
+  Pop "${ResultVar}"
+!macroend
+!define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"'
+ 
+!macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
+  Push "${EnvVarName}"
+  Push "${Action}"
+  Push "${RegLoc}"
+  Push "${PathString}"
+    Call un.EnvVarUpdate
+  Pop "${ResultVar}"
+!macroend
+!define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"'
+; ---------------------------------- Macro Definitions end-------------------------------------
+ 
+;----------------------------------- EnvVarUpdate start----------------------------------------
+!define hklm_all_users     'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
+!define hkcu_current_user  'HKCU "Environment"'
+ 
+!macro EnvVarUpdate UN
+ 
+Function ${UN}EnvVarUpdate
+ 
+  Push $0
+  Exch 4
+  Exch $1
+  Exch 3
+  Exch $2
+  Exch 2
+  Exch $3
+  Exch
+  Exch $4
+  Push $5
+  Push $6
+  Push $7
+  Push $8
+  Push $9
+  Push $R0
+ 
+  /* After this point:
+  -------------------------
+     $0 = ResultVar     (returned)
+     $1 = EnvVarName    (input)
+     $2 = Action        (input)
+     $3 = RegLoc        (input)
+     $4 = PathString    (input)
+     $5 = Orig EnvVar   (read from registry)
+     $6 = Len of $0     (temp)
+     $7 = tempstr1      (temp)
+     $8 = Entry counter (temp)
+     $9 = tempstr2      (temp)
+     $R0 = tempChar     (temp)  */
+ 
+  ; Step 1:  Read contents of EnvVarName from RegLoc
+  ;
+  ; Check for empty EnvVarName
+  ${If} $1 == ""
+    SetErrors
+    DetailPrint "ERROR: EnvVarName is blank"
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+ 
+  ; Check for valid Action
+  ${If}    $2 != "A"
+  ${AndIf} $2 != "P"
+  ${AndIf} $2 != "R"
+    SetErrors
+    DetailPrint "ERROR: Invalid Action - must be A, P, or R"
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+ 
+  ${If} $3 == HKLM
+    ReadRegStr $5 ${hklm_all_users} $1     ; Get EnvVarName from all users into $5
+  ${ElseIf} $3 == HKCU
+    ReadRegStr $5 ${hkcu_current_user} $1  ; Read EnvVarName from current user into $5
+  ${Else}
+    SetErrors
+    DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"'
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+ 
+  ; Check for empty PathString
+  ${If} $4 == ""
+    SetErrors
+    DetailPrint "ERROR: PathString is blank"
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+ 
+  Push $6
+  Push $7
+  Push $8
+  StrLen $7 $4  
+  StrLen $6 $5
+  IntOp $8 $6 + $7
+  ${If} $5 == ""
+  ${OrIf} $8 >= ${NSIS_MAX_STRLEN}
+    SetErrors
+    DetailPrint "Current $1 length ($6) too long to modify in NSIS; set manually if needed"
+    Pop $8
+    Pop $7
+    Pop $6
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+  Pop $8
+  Pop $7
+  Pop $6
+
+  ; Make sure we've got some work to do
+  ${If} $5 == ""
+  ${AndIf} $2 == "R"
+    SetErrors
+    DetailPrint "$1 is empty - Nothing to remove"
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+ 
+  ; Step 2: Scrub EnvVar
+  ;
+  StrCpy $0 $5                             ; Copy the contents to $0
+  ; Remove spaces around semicolons (NOTE: spaces before the 1st entry or
+  ; after the last one are not removed here but instead in Step 3)
+  ${If} $0 != ""                           ; If EnvVar is not empty ...
+    ${Do}
+      ${${UN}StrStr} $7 $0 " ;"
+      ${If} $7 == ""
+        ${ExitDo}
+      ${EndIf}
+      ${${UN}StrRep} $0  $0 " ;" ";"         ; Remove '<space>;'
+    ${Loop}
+    ${Do}
+      ${${UN}StrStr} $7 $0 "; "
+      ${If} $7 == ""
+        ${ExitDo}
+      ${EndIf}
+      ${${UN}StrRep} $0  $0 "; " ";"         ; Remove ';<space>'
+    ${Loop}
+    ${Do}
+      ${${UN}StrStr} $7 $0 ";;" 
+      ${If} $7 == ""
+        ${ExitDo}
+      ${EndIf}
+      ${${UN}StrRep} $0  $0 ";;" ";"
+    ${Loop}
+ 
+    ; Remove a leading or trailing semicolon from EnvVar
+    StrCpy  $7  $0 1 0
+    ${If} $7 == ";"
+      StrCpy $0  $0 "" 1                   ; Change ';<EnvVar>' to '<EnvVar>'
+    ${EndIf}
+    StrLen $6 $0
+    IntOp $6 $6 - 1
+    StrCpy $7  $0 1 $6
+    ${If} $7 == ";"
+     StrCpy $0  $0 $6                      ; Change ';<EnvVar>' to '<EnvVar>'
+    ${EndIf}
+    ; DetailPrint "Scrubbed $1: [$0]"      ; Uncomment to debug
+  ${EndIf}
+ 
+  /* Step 3. Remove all instances of the target path/string (even if "A" or "P")
+     $6 = bool flag (1 = found and removed PathString)
+     $7 = a string (e.g. path) delimited by semicolon(s)
+     $8 = entry counter starting at 0
+     $9 = copy of $0
+     $R0 = tempChar      */
+ 
+  ${If} $5 != ""                           ; If EnvVar is not empty ...
+    StrCpy $9 $0
+    StrCpy $0 ""
+    StrCpy $8 0
+    StrCpy $6 0
+ 
+    ${Do}
+      ${${UN}StrTok} $7 $9 ";" $8 "0"      ; $7 = next entry, $8 = entry counter
+ 
+      ${If} $7 == ""                       ; If we've run out of entries,
+        ${ExitDo}                          ;    were done
+      ${EndIf}                             ;
+ 
+      ; Remove leading and trailing spaces from this entry (critical step for Action=Remove)
+      ${Do}
+        StrCpy $R0  $7 1
+        ${If} $R0 != " "
+          ${ExitDo}
+        ${EndIf}
+        StrCpy $7   $7 "" 1                ;  Remove leading space
+      ${Loop}
+      ${Do}
+        StrCpy $R0  $7 1 -1
+        ${If} $R0 != " "
+          ${ExitDo}
+        ${EndIf}
+        StrCpy $7   $7 -1                  ;  Remove trailing space
+      ${Loop}
+      ${If} $7 == $4                       ; If string matches, remove it by not appending it
+        StrCpy $6 1                        ; Set 'found' flag
+      ${ElseIf} $7 != $4                   ; If string does NOT match
+      ${AndIf}  $0 == ""                   ;    and the 1st string being added to $0,
+        StrCpy $0 $7                       ;    copy it to $0 without a prepended semicolon
+      ${ElseIf} $7 != $4                   ; If string does NOT match
+      ${AndIf}  $0 != ""                   ;    and this is NOT the 1st string to be added to $0,
+        StrCpy $0 $0;$7                    ;    append path to $0 with a prepended semicolon
+      ${EndIf}                             ;
+ 
+      IntOp $8 $8 + 1                      ; Bump counter
+    ${Loop}                                ; Check for duplicates until we run out of paths
+  ${EndIf}
+ 
+  ; Step 4:  Perform the requested Action
+  ;
+  ${If} $2 != "R"                          ; If Append or Prepend
+    ${If} $6 == 1                          ; And if we found the target
+      DetailPrint "Target is already present in $1. It will be removed and"
+    ${EndIf}
+    ${If} $0 == ""                         ; If EnvVar is (now) empty
+      StrCpy $0 $4                         ;   just copy PathString to EnvVar
+      ${If} $6 == 0                        ; If found flag is either 0
+      ${OrIf} $6 == ""                     ; or blank (if EnvVarName is empty)
+        DetailPrint "$1 was empty and has been updated with the target"
+      ${EndIf}
+    ${ElseIf} $2 == "A"                    ;  If Append (and EnvVar is not empty),
+      StrCpy $0 $0;$4                      ;     append PathString
+      ${If} $6 == 1
+        DetailPrint "appended to $1"
+      ${Else}
+        DetailPrint "Target was appended to $1"
+      ${EndIf}
+    ${Else}                                ;  If Prepend (and EnvVar is not empty),
+      StrCpy $0 $4;$0                      ;     prepend PathString
+      ${If} $6 == 1
+        DetailPrint "prepended to $1"
+      ${Else}
+        DetailPrint "Target was prepended to $1"
+      ${EndIf}
+    ${EndIf}
+  ${Else}                                  ; If Action = Remove
+    ${If} $6 == 1                          ;   and we found the target
+      DetailPrint "Target was found and removed from $1"
+    ${Else}
+      DetailPrint "Target was NOT found in $1 (nothing to remove)"
+    ${EndIf}
+    ${If} $0 == ""
+      DetailPrint "$1 is now empty"
+    ${EndIf}
+  ${EndIf}
+ 
+  ; Step 5:  Update the registry at RegLoc with the updated EnvVar and announce the change
+  ;
+  ClearErrors
+  ${If} $3  == HKLM
+    WriteRegExpandStr ${hklm_all_users} $1 $0     ; Write it in all users section
+  ${ElseIf} $3 == HKCU
+    WriteRegExpandStr ${hkcu_current_user} $1 $0  ; Write it to current user section
+  ${EndIf}
+ 
+  IfErrors 0 +4
+    MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3"
+    DetailPrint "Could not write updated $1 to $3"
+    Goto EnvVarUpdate_Restore_Vars
+ 
+  ; "Export" our change
+  SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
+ 
+  EnvVarUpdate_Restore_Vars:
+  ;
+  ; Restore the user's variables and return ResultVar
+  Pop $R0
+  Pop $9
+  Pop $8
+  Pop $7
+  Pop $6
+  Pop $5
+  Pop $4
+  Pop $3
+  Pop $2
+  Pop $1
+  Push $0  ; Push my $0 (ResultVar)
+  Exch
+  Pop $0   ; Restore his $0
+ 
+FunctionEnd
+ 
+!macroend   ; EnvVarUpdate UN
+!insertmacro EnvVarUpdate ""
+!insertmacro EnvVarUpdate "un."
+;----------------------------------- EnvVarUpdate end----------------------------------------
+ 
+!verbose pop
+!endif
diff --git a/tools/niminst/nsis.tmpl b/tools/niminst/nsis.tmpl
index 7249dca63..c4270081e 100644
--- a/tools/niminst/nsis.tmpl
+++ b/tools/niminst/nsis.tmpl
@@ -3,170 +3,253 @@
 #  result = "; NSIS script generated by niminst\n" &
 #           "; To regenerate run ``niminst nsis`` or ``koch nsis``\n"
 
-!define PRODUCT_NAME "?c.displayName"
-!define PRODUCT_VERSION "?c.version"
-!define PRODUCT_PUBLISHER "?c.authors"
-!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\?{c.name}.exe"
-!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
-!define PRODUCT_UNINST_ROOT_KEY "HKCU"
-!define PRODUCT_STARTMENU_REGVAL "NSIS:StartMenuDir"
-
-; MUI 1.67 compatible ------
-!include "MUI.nsh"
-!define MULTIUSER_EXECUTIONLEVEL Standard
-!include "MultiUser.nsh"
-!include "zipdll.nsh"
-
-InstallDir "$LOCALAPPDATA\?{c.name}"
-
-; MUI Settings
-!define MUI_ABORTWARNING
-!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
-!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
-
-; Welcome page
-!insertmacro MUI_PAGE_WELCOME
-; License page
-!insertmacro MUI_PAGE_LICENSE "?{expandFilename(c.license)}"
-; Components page
-!insertmacro MUI_PAGE_COMPONENTS
-; Directory page
-!insertmacro MUI_PAGE_DIRECTORY
-; Start menu page
-var ICONS_GROUP
-!define MUI_STARTMENUPAGE_NODISABLE
-!define MUI_STARTMENUPAGE_DEFAULTFOLDER "?c.displayName"
-!define MUI_STARTMENUPAGE_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
-!define MUI_STARTMENUPAGE_REGISTRY_KEY "${PRODUCT_UNINST_KEY}"
-!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${PRODUCT_STARTMENU_REGVAL}"
-!insertmacro MUI_PAGE_STARTMENU Application $ICONS_GROUP
-; Instfiles page
-!insertmacro MUI_PAGE_INSTFILES
-; Finish page
-; !define MUI_FINISHPAGE_RUN "$INSTDIR\start.bat"
-!insertmacro MUI_PAGE_FINISH
-
-; Uninstaller pages
-!insertmacro MUI_UNPAGE_INSTFILES
-
-; Language files
-!insertmacro MUI_LANGUAGE "English"
-
-; MUI end ------
-
-Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
-OutFile "?{c.name}_?{c.version}.exe"
-; InstallDir "$PROGRAMFILES\?c.displayName"
-InstallDirRegKey HKCU "${PRODUCT_DIR_REGKEY}" ""
-ShowInstDetails show
-ShowUnInstDetails show
-
-Section "Core" SEC0
-  SetOverwrite ifnewer
-  SetOutPath "$INSTDIR"
-  #for i in low(TFileCategory)..fcWindows:
-  #  for f in items(c.cat[i]):
-       SetOutPath "$INSTDIR\?{splitFile(f).dir.toWin}"
-       File "?{expandFilename(f).toWin}"
-  #  end for
-  #end for
-
-
-; Shortcuts
-  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
-  CreateDirectory "$SMPROGRAMS\$ICONS_GROUP"
-
-  #if c.app == appConsole:
-    CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{c.displayName}.lnk" "$INSTDIR\start.bat"
-    CreateShortCut "$DESKTOP\?{c.displayName}.lnk" "$INSTDIR\start.bat"
-  #else:
-    CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{c.displayName}.lnk" "$INSTDIR\?{c.name}.exe"
-    CreateShortCut "$DESKTOP\?{c.displayName}.lnk" "$INSTDIR\?{c.name}.exe"
-  #end if
-  #for f in items(c.cat[fcDocStart]):
-    CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{splitFile(f).name}.lnk" "$INSTDIR\?{f.toWin}"
-  #end for
-
-  !insertmacro MUI_STARTMENU_WRITE_END
-SectionEnd
-
-#var i = 0
-#for download in c.downloads:
-#  inc i
-#  let d = download.split('|')
-#  if d.len != 5 and d.len != 6:
-#    quit("download string needs 5..6 parts: " & download)
-#  end if
-#  let sectionName = d[0]
-#  let dir = d[1]
-#  let zipName = d[2]
-#  let size = d[3]
-#  let url = d[4]
-  Section /o "?sectionName" SEC?i
-
-  AddSize ?size
-
-  NSISdl::download "?url" "$INSTDIR\?zipName"
-  Pop $0
-  ${If} $0 == "success"
-    ZipDLL::extractall "$INSTDIR\?zipName" "$INSTDIR\?dir"
-    Delete "$INSTDIR\?zipName"
-  ${Else}
-    MessageBox mb_iconstop "Error: $0" ;Show cancel/error message
-  ${EndIf}
-
-#  if d.len >= 6:
-#    let startMenuEntry = d[5]
-#    let e = splitFile(startMenuEntry).name.capitalize
-    CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{e}.lnk" "$INSTDIR\?dir\?{startMenuEntry.toWin}"
-#  end if
-
-; Shortcuts
-  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
-  !insertmacro MUI_STARTMENU_WRITE_END
+;--------------------------------
+; Included headers
+  ; Modern User Interface 2.0 Header
+  !include "MUI2.nsh"
+
+  ; File Functions Header, used to get the current drive root.
+  !include "FileFunc.nsh"
+
+  ; *Patched* Environment Variable Manipulation Header, used to add
+  ; tools to the user's PATH environment variable.
+  !include "EnvVarUpdate.nsh"
+
+;--------------------------------
+; Global variables and defines
+  !define PRODUCT_NAME "?c.displayName"
+  !define PRODUCT_VERSION "?c.version"
+  !define PRODUCT_PUBLISHER "?c.authors"
+  !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\?{c.name}.exe"
+  !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
+  !define PRODUCT_UNINST_ROOT_KEY "HKCU"
+  !define PRODUCT_STARTMENU_REGVAL "NSIS:StartMenuDir"
+
+
+;--------------------------------
+; General Setup Information
+
+  ; Name and output file
+  Name "?{c.name} ?{c.version}"
+  OutFile "?{c.name}_?{c.version}.exe"
+
+  ; Default installation folder
+  ; This is changed later (in .onInit) to the root directory, if possible.
+  InstallDir "$LOCALAPPDATA\?{c.name}"
+  
+  ; Get installation folder from registry if available
+  InstallDirRegKey HKCU "Software\c.name\c.version" ""
+
+  ; Request user level application privileges.
+  RequestExecutionLevel user
+
+  ; Allow installation to the root drive directory.
+  AllowRootDirInstall true
+
+  ; Maximum compression!
+  SetCompressor /SOLID /FINAL lzma
+
+  ; Installer and Uninstaller Icons
+  ; Icon "nimrod.ico"
+  ; UninstallIcon "nimrod.ico"
+
+  ; Set installation details to be shown by default
+  ShowInstDetails show
+  ShowUnInstDetails show
+
+;--------------------------------
+; Interface Settings
+
+  ; Warn the user if aborting during installation/uninstallation
+  !define MUI_ABORTWARNING
+  !define MUI_UNABORTWARNING
+
+  ; Don't show a description for sections
+  !define MUI_COMPONENTSPAGE_NODESC
+
+;--------------------------------
+; Pages
+
+  ; Setup the installer pages
+  !insertmacro MUI_PAGE_WELCOME
+  !insertmacro MUI_PAGE_LICENSE "?{expandFilename(c.license)}"
+  !insertmacro MUI_PAGE_COMPONENTS
+  !insertmacro MUI_PAGE_DIRECTORY
+
+  ; Setup the start menu entry page
+  var ICONS_GROUP
+  !define MUI_STARTMENUPAGE_DEFAULTFOLDER "?{c.displayName}"
+  !define MUI_STARTMENUPAGE_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
+  !define MUI_STARTMENUPAGE_REGISTRY_KEY "${PRODUCT_UNINST_KEY}"
+  !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${PRODUCT_STARTMENU_REGVAL}"
+  !insertmacro MUI_PAGE_STARTMENU Application $ICONS_GROUP
+
+  !insertmacro MUI_PAGE_INSTFILES
+  !insertmacro MUI_PAGE_FINISH
+  
+  ; Setup the uninstaller pages
+  !insertmacro MUI_UNPAGE_CONFIRM
+  !insertmacro MUI_UNPAGE_INSTFILES
+  
+;--------------------------------
+;Languages
+ 
+  !insertmacro MUI_LANGUAGE "English"
+
+;--------------------------------
+;Installer Sections
+
+  ; The core section. This is comprised of a base Nim installation,
+  ; such as what would be retrieved via git, and an already bootstrapped
+  ; Nim binary.
+  Section "Core Files" CoreSection
+    ; This is a mandotory section
+    SectionIn RO 
+
+    ; Output files to the base installation directory
+    SetOutPath "$INSTDIR"
+
+    ; Only overwrite newer files
+    SetOverwrite ifnewer
+
+    ; Write all the files to the output directory.
+    #for i in low(TFileCategory)..fcWindows:
+    #  for f in items(c.cat[i]):
+         SetOutPath "$INSTDIR\?{splitFile(f).dir.toWin}"
+         File "?{expandFilename(f).toWin}"
+    #  end for
+    #end for
+
+    ; Write out the uninstaller
+    WriteUninstaller "$INSTDIR\uninstaller.exe"
   SectionEnd
-#end
-
-Section -AdditionalIcons
-  SetOutPath $INSTDIR
-  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
-  CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Uninstall.lnk" "$INSTDIR\uninst.exe"
-  !insertmacro MUI_STARTMENU_WRITE_END
-SectionEnd
-
-Section -Post
-  WriteUninstaller "$INSTDIR\uninst.exe"
-  WriteRegStr HKCU "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\bin\?{c.name}.exe"
-  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
-  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
-  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\bin\?{c.name}.exe"
-  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
-  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
-SectionEnd
-
-Function .onInit
-  !insertmacro MULTIUSER_INIT
-FunctionEnd
-
-Function un.onUninstSuccess
-  HideWindow
-  MessageBox MB_ICONINFORMATION|MB_OK "Uninstall was completed successfully."
-FunctionEnd
-
-Function un.onInit
-  MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Remove $(^Name) from your computer." IDYES +2
-  Abort
-  !insertmacro MULTIUSER_UNINIT
-FunctionEnd
-
-Section Uninstall
-  !insertmacro MUI_STARTMENU_GETFOLDER "Application" $ICONS_GROUP
-  Delete "$DESKTOP\?{c.displayName}.lnk"
-
-  RMDir /r "$SMPROGRAMS\$ICONS_GROUP"
-  RMDir /r "$INSTDIR"
-
-  DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
-  DeleteRegKey HKCU "${PRODUCT_DIR_REGKEY}"
-  SetAutoClose true
-SectionEnd
\ No newline at end of file
+
+  Section "-Add Registry Keys" RegistrySection
+    ; Write application registry keys
+    WriteRegStr HKCU "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\bin\?{c.name}.exe"
+    WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
+    WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
+    WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\bin\?{c.name}.exe"
+    WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
+    WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
+    ; Reset the output path
+    SetOutPath "$INSTDIR"
+  SectionEnd
+
+  ; Section for adding the shortcuts related to files and applications
+  Section "-Setup Shortcuts" ShortcutsSection
+    !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
+      CreateDirectory "$SMPROGRAMS\$ICONS_GROUP"
+
+      #if c.app == appConsole:
+        CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{c.displayName}.lnk" "$INSTDIR\start.bat"
+        CreateShortCut "$DESKTOP\?{c.displayName}.lnk" "$INSTDIR\start.bat"
+      #else:
+        CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{c.displayName}.lnk" "$INSTDIR\?{c.name}.exe"
+        CreateShortCut "$DESKTOP\?{c.displayName}.lnk" "$INSTDIR\?{c.name}.exe"
+      #end if
+
+      ; Add shortcuts for the documentation
+      #for f in items(c.cat[fcDocStart]):
+        CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{splitFile(f).name}.lnk" "$INSTDIR\?{f.toWin}"
+      #end for
+
+      ; Write the shortcut to the uninstaller
+      CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Uninstall.lnk" "$INSTDIR\uninstaller.exe"
+    !insertmacro MUI_STARTMENU_WRITE_END
+  SectionEnd
+
+  ; Section for adding tools to the PATH variable
+  Section "Setup Path Environment" PathSection
+     ${EnvVarUpdate} $R0 "PATH" "A" "HKCU" "$INSTDIR\dist\mingw"
+     ${EnvVarUpdate} $R0 "PATH" "A" "HKCU" "$INSTDIR\bin"
+     ${EnvVarUpdate} $R0 "PATH" "A" "HKCU" "$INSTDIR\dist\babel"
+  SectionEnd
+
+  ; The downloadable sections. These sections are automatically generated by
+  ; niminst and the template filters.
+  #var i = 0 
+  #for download in c.downloads:
+  #  inc i
+  #  let d = download.split('|')
+  #  if d.len != 5 and d.len != 6:
+  #    quit("download string needs 5..6 parts: " & download)
+  #  end if
+  #  let sectionName = d[0]
+  #  let dir = d[1]
+  #  let zipName = d[2]
+  #  let size = d[3]
+  #  let url = d[4]
+  Section /o "?sectionName" ?{i}Section
+    ; Add the section size to the total size.
+    AddSize ?size
+
+    ; Download the file, and if successful, extract it to the given directory
+    ; otherwise,
+    retry:
+    NSISdl::download "?url" "$TEMP\?zipName"
+    Pop $0
+    ${If} $0 == "success"
+      ZipDLL::extractall "$TEMP\?zipName" "$INSTDIR\?dir"
+      Delete "$TEMP\?zipName"
+    ${Else}
+      MessageBox MB_ICONSTOP|MB_ABORTRETRYIGNORE "Error: $0" IDRETRY retry IDIGNORE ignore
+      abort
+    ${EndIf}
+
+    #  if d.len >= 6:
+    #    let startMenuEntry = d[5]
+    #    let e = splitFile(startMenuEntry).name.capitalize
+      CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{e}.lnk" "$INSTDIR\?dir\?{startMenuEntry.toWin}"
+    #  end if
+
+    ; Shortcuts
+      !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
+      !insertmacro MUI_STARTMENU_WRITE_END
+    ignore:
+  SectionEnd
+  #end
+
+;--------------------------------
+; Section Descriptions
+  ; Series of strings describing each section
+  ; LangString DESC_CoreSection ${LANG_ENGLISH} "Core Nim files"
+
+  ; The macros to actually insert the descriptions into the sections.
+  ; Each description above should have a corresponding MUI_DESCRIPTION_TEXT
+  ; macro linking the section to the description.
+  ; !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
+  ;   !insertmacro MUI_DESCRIPTION_TEXT ${CoreSection} $(DESC_CoreSection)
+  ; !insertmacro MUI_FUNCTION_DESCRIPTION_END
+
+
+;--------------------------------
+; Uninstaller Sections
+
+  Section "Uninstall"
+    ; Remove previously created shortcuts
+    !insertmacro MUI_STARTMENU_GETFOLDER "Application" $ICONS_GROUP
+    Delete "$DESKTOP\?{c.displayName}.lnk"
+
+    ; Remove installed application files
+    RMDir /r "$SMPROGRAMS\$ICONS_GROUP"
+    RMDir /r "$INSTDIR"
+
+    ; Remove the previously created registry key
+    DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
+    DeleteRegKey HKCU "${PRODUCT_DIR_REGKEY}"
+    SetAutoClose true
+
+    ; Remove entries from the PATH environment variable
+    ${un.EnvVarUpdate} $R0 "PATH" "R" "HKCU" "$INSTDIR\dist\mingw"
+    ${un.EnvVarUpdate} $R0 "PATH" "R" "HKCU" "$INSTDIR\bin"
+    ${un.EnvVarUpdate} $R0 "PATH" "R" "HKCU" "$INSTDIR\dist\babel"
+  SectionEnd
+
+;--------------------------------
+; Function hooks
+
+  Function .onInit
+    ${GetRoot} "$EXEDIR" $R0
+    strCpy $INSTDIR "$R0\?{c.name}"
+  FunctionEnd
\ No newline at end of file