scriptable-client-installers/tools/Include/Memento.nsh
2023-12-15 16:09:19 -05:00

554 lines
10 KiB
Plaintext

!verbose push
!verbose 3
!include LogicLib.nsh
!include Sections.nsh
!ifndef ___MEMENTO_NSH___
!define ___MEMENTO_NSH___
#####################################
### Memento ###
#####################################
/*
Memento is a set of macros that allow installers to remember user selection
across separate runs of the installer. Currently, it can remember the state
of sections and mark new sections as bold. In the future, it'll integrate
InstallOptions and maybe even the Modern UI.
A usage example can be found in `Examples\Memento.nsi`.
*/
#####################################
### Usage Instructions ###
#####################################
/*
1. Declare usage of Memento by including Memento.nsh at the top of the script.
!include Memento.nsh
2. Define MEMENTO_REGISTRY_ROOT and MEMENTO_REGISTRY_KEY with the a registry key
where sections' state should be saved.
!define MEMENTO_REGISTRY_ROOT HKLM
!define MEMENTO_REGISTRY_KEY \
Software\Microsoft\Windows\CurrentVersion\Uninstall\MyProgram
3. Replace Section with ${MementoSection} and SectionEnd with ${MementoSectionEnd}
for sections that whose state should be remembered by Memento.
For sections that should be unselected by default, use ${MementoSection}'s
brother - ${MementoUnselectedSection}.
Sections that don't already have an identifier must be assigned one.
Section identifiers must stay the same across different versions of the
installer or their state will be forgotten.
4. Use ${MementoSectionDone} after the last ${MementoSection}.
5. Add a call to ${MementoSectionRestore} to .onInit to restore the state
of all sections from the registry.
Function .onInit
${MementoSectionRestore}
FunctionEnd
6. Add a call to ${MementoSectionSave} to .onInstSuccess to save the state
of all sections to the registry.
Function .onInstSuccess
${MementoSectionSave}
FunctionEnd
7. Tattoo the location of the chosen registry key on your arm.
*/
#####################################
### User API ###
#####################################
;
; ${MementoSection}
;
; Defines a section whose state is remembered by Memento.
;
; Usage is similar to Section.
;
; ${MementoSection} "name" "some_id"
;
!define MementoSection "!insertmacro MementoSection"
;
; ${MementoSectionEnd}
;
; Ends a section previously opened using ${MementoSection}.
;
; Usage is similar to SectionEnd.
;
; ${MementoSection} "name" "some_id"
; # some code...
; ${MementoSectionEnd}
;
;
; ${MementoUnselectedSection}
;
; Defines a section whose state is remembered by Memento and is
; unselected by default.
;
; Usage is similar to Section with the /o switch.
;
; ${MementoUnselectedSection} "name" "some_id"
;
!define MementoUnselectedSection "!insertmacro MementoUnselectedSection"
;
; ${MementoSectionEnd}
;
; Ends a section previously opened using ${MementoSection}.
;
; Usage is similar to SectionEnd.
;
; ${MementoSection} "name" "some_id"
; # some code...
; ${MementoSectionEnd}
;
!define MementoSectionEnd "!insertmacro MementoSectionEnd"
;
; ${MementoSectionDone}
;
; Used after all ${MementoSection} have been set.
;
; ${MementoSection} "name1" "some_id1"
; # some code...
; ${MementoSectionEnd}
;
; ${MementoSection} "name2" "some_id2"
; # some code...
; ${MementoSectionEnd}
;
; ${MementoSection} "name3" "some_id3"
; # some code...
; ${MementoSectionEnd}
;
; ${MementoSectionDone}
;
!define MementoSectionDone "!insertmacro MementoSectionDone"
;
; ${MementoSectionRestore}
;
; Restores the state of all Memento sections from the registry.
;
; Commonly used in .onInit.
;
; Function .onInit
;
; ${MementoSectionRestore}
;
; FunctionEnd
;
!define MementoSectionRestore "!insertmacro MementoSectionRestore"
;
; ${MementoSectionSave}
;
; Saves the state of all Memento sections to the registry.
;
; Commonly used in .onInstSuccess.
;
; Function .onInstSuccess
;
; ${MementoSectionSave}
;
; FunctionEnd
;
!define MementoSectionSave "!insertmacro MementoSectionSave"
;
; MementoSection<ReadWrite><Int|Marker>
;
; Replaceable macros that allow custom storage methods to be used.
;
!ifmacrondef MementoSectionReadInt
!define __MementoSectionStdRegReadWrite
!macro MementoSectionReadInt outvar name
ReadRegDWord ${outvar} ${MEMENTO_REGISTRY_ROOT} `${MEMENTO_REGISTRY_KEY}` `MementoSection${name}`
!macroend
!macro MementoSectionWriteInt name val
WriteRegDWord ${MEMENTO_REGISTRY_ROOT} `${MEMENTO_REGISTRY_KEY}` `MementoSection${name}` `${val}`
!macroend
!macro MementoSectionReadMarker outvar name
ReadRegStr ${outvar} ${MEMENTO_REGISTRY_ROOT} `${MEMENTO_REGISTRY_KEY}` `MementoSection${name}`
!macroend
!macro MementoSectionWriteMarker name
WriteRegStr ${MEMENTO_REGISTRY_ROOT} `${MEMENTO_REGISTRY_KEY}` `MementoSection${name}` ``
!macroend
!endif
#####################################
### Internal Defines ###
#####################################
!define __MementoSectionIndex 1
#####################################
### Internal Macros ###
#####################################
!macro __MementoCheckSettings
!ifdef __MementoSectionStdRegReadWrite
!ifndef MEMENTO_REGISTRY_ROOT | MEMENTO_REGISTRY_KEY
!error "MEMENTO_REGISTRY_ROOT and MEMENTO_REGISTRY_KEY must be defined before using any of Memento's macros"
!endif
!endif
!macroend
!macro __MementoSection flags name id
!insertmacro __MementoCheckSettings
!ifndef __MementoSectionIndex
!error "MementoSectionDone already used!"
!endif
!define __MementoSectionLastSectionId `${id}`
!verbose pop
Section ${flags} `${name}` `${id}`
!verbose push
!verbose 3
!macroend
#####################################
### User Macros ###
#####################################
!macro MementoSection name id
!verbose push
!verbose 3
!insertmacro __MementoSection "" `${name}` `${id}`
!verbose pop
!macroend
!macro MementoUnselectedSection name id
!verbose push
!verbose 3
!insertmacro __MementoSection /o `${name}` `${id}`
!define __MementoSectionUnselected
!verbose pop
!macroend
!macro MementoSectionEnd
SectionEnd
!verbose push
!verbose 3
!insertmacro __MementoCheckSettings
!ifndef __MementoSectionIndex
!error "MementoSectionDone already used!"
!endif
!define /MATH __MementoSectionIndexNext \
${__MementoSectionIndex} + 1
Function __MementoSectionMarkNew${__MementoSectionIndex}
ClearErrors
!insertmacro MementoSectionReadInt $0 `_${__MementoSectionLastSectionId}`
${If} ${Errors}
!insertmacro SetSectionFlag `${${__MementoSectionLastSectionId}}` ${SF_BOLD}
${EndIf}
GetFunctionAddress $0 __MementoSectionMarkNew${__MementoSectionIndexNext}
Goto $0
FunctionEnd
Function __MementoSectionRestoreStatus${__MementoSectionIndex}
ClearErrors
!insertmacro MementoSectionReadInt $0 `_${__MementoSectionLastSectionId}`
!ifndef __MementoSectionUnselected
${If} ${Errors}
${OrIf} $0 != 0
!insertmacro SelectSection `${${__MementoSectionLastSectionId}}`
${Else}
!insertmacro UnselectSection `${${__MementoSectionLastSectionId}}`
${EndIf}
!else
!undef __MementoSectionUnselected
${If} ${Errors}
${OrIf} $0 == 0
!insertmacro UnselectSection `${${__MementoSectionLastSectionId}}`
${Else}
!insertmacro SelectSection `${${__MementoSectionLastSectionId}}`
${EndIf}
!endif
GetFunctionAddress $0 __MementoSectionRestoreStatus${__MementoSectionIndexNext}
Goto $0
FunctionEnd
Function __MementoSectionSaveStatus${__MementoSectionIndex}
${If} ${SectionIsSelected} `${${__MementoSectionLastSectionId}}`
!insertmacro MementoSectionWriteInt `_${__MementoSectionLastSectionId}` 1
${Else}
!insertmacro MementoSectionWriteInt `_${__MementoSectionLastSectionId}` 0
${EndIf}
GetFunctionAddress $0 __MementoSectionSaveStatus${__MementoSectionIndexNext}
Goto $0
FunctionEnd
!undef __MementoSectionIndex
!define __MementoSectionIndex ${__MementoSectionIndexNext}
!undef __MementoSectionIndexNext
!undef __MementoSectionLastSectionId
!verbose pop
!macroend
!macro MementoSectionDone
!verbose push
!verbose 3
!insertmacro __MementoCheckSettings
Function __MementoSectionMarkNew${__MementoSectionIndex}
FunctionEnd
Function __MementoSectionRestoreStatus${__MementoSectionIndex}
FunctionEnd
Function __MementoSectionSaveStatus${__MementoSectionIndex}
FunctionEnd
!undef __MementoSectionIndex
!verbose pop
!macroend
!macro MementoSectionRestore
!verbose push
!verbose 3
!insertmacro __MementoCheckSettings
Push $0
Push $1
Push $2
Push $3
# check for first usage
ClearErrors
!insertmacro MementoSectionReadMarker $0 `Used`
${If} ${Errors}
# use script defaults on first run
Goto done
${EndIf}
# mark new components in bold
Call __MementoSectionMarkNew1
# mark section groups in bold
StrCpy $0 0
StrCpy $1 ""
StrCpy $2 ""
StrCpy $3 ""
loop:
ClearErrors
${If} ${SectionIsBold} $0
${If} $1 != ""
!insertmacro SetSectionFlag $1 ${SF_BOLD}
${EndIf}
${If} $2 != ""
!insertmacro SetSectionFlag $2 ${SF_BOLD}
${EndIf}
${If} $3 != ""
!insertmacro SetSectionFlag $3 ${SF_BOLD}
${EndIf}
${ElseIf} ${Errors}
Goto loop_end
${EndIf}
${If} ${SectionIsSectionGroup} $0
${If} $1 == ""
StrCpy $1 $0
${ElseIf} $2 == ""
StrCpy $2 $0
${ElseIf} $3 == ""
StrCpy $3 $0
${EndIf}
${EndIf}
${If} ${SectionIsSectionGroupEnd} $0
${If} $3 != ""
StrCpy $3 ""
${ElseIf} $2 != ""
StrCpy $2 ""
${ElseIf} $1 != ""
StrCpy $1 ""
${EndIf}
${EndIf}
IntOp $0 $0 + 1
Goto loop
loop_end:
# restore sections' status
Call __MementoSectionRestoreStatus1
# all done
done:
Pop $3
Pop $2
Pop $1
Pop $0
!verbose pop
!macroend
!macro MementoSectionSave
!verbose push
!verbose 3
!insertmacro __MementoCheckSettings
Push $0
!insertmacro MementoSectionWriteMarker `Used`
Call __MementoSectionSaveStatus1
Pop $0
!verbose pop
!macroend
!endif # ___MEMENTO_NSH___
!verbose pop