Notepad++ Setup

Revision as of 02:46, 16 August 2019 by imported>Whisper (Extra NppExec option to deal with namespaces.)

Notepad++ is a freeware text editor that can be used to edit and compile Papyrus scripts. It can be downloaded from the official Notepad++ site. Notepad++ supports user-defined syntax highlighting autocomplete, folding, and can be set up to quickly compile Papyrus scripts, making it a more robust option than using the basic in-editor text editor.

Setting up a quick compile

  1. Open Notepad++
  2. Hit F5 (run)
  3. Paste the following line into the input in the "Run..." dialogue window in Notepad++:
    "C:\Program Files (x86)\Steam\steamapps\common\skyrim\Papyrus Compiler\ScriptCompile.bat" "$(FILE_NAME)" "$(CURRENT_DIRECTORY)"
    NOTE: Inside the first quotes, paste in the equivalent path on your PC that points to the ScriptCompile.bat file.
  4. Select Save...
  5. Name it something useful like "Compile Papyrus"
  6. Set up a keyboard shortcut if you want, such as CTRL+F5.
  • You can find the new shortcut under the Run menu option, or just use your keyboard shortcut if you defined one. (If you attempt to use the shortcut and nothing happens, double check that you have linked the shortcut to the ScriptCompile.bat file, and not the PapyrusCompiler.exe)
  • You can change the keyboard shortcut under Run -> Modify Shortcut/Delete Command
  • This will compile the script you are currently tabbed to while in Notepad++.
  • NOTE: By default and after any Creation Kit updates, you'll find the batch file will not work initially as it's pointed to Bethesda's developer directory. To set it up for your Skyrim installation, Right-Click > Edit "Skyrim\Papyrus Compiler\ScriptCompile.bat" and make sure its filepaths are pointed to your Skyrim. For a default installation, the following should work
cd %2
"%~dp0PapyrusCompiler" %1 -f="TESV_Papyrus_Flags.flg" -i="%~dp0..\Data\Scripts\Source" -o="%~dp0..\Data\Scripts"
pause

Advanced Compiler

There is also a more advanced compiler script avaiable that offers the feature of defining additional import directories and some more comfort.

@ECHO OFF
mode 100,50
VERIFY > nul
CLS
:: read Skyrim path from registry and write the line containing the result to a temporary file
if %PROCESSOR_ARCHITECTURE%==x86 (
  REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Bethesda Softworks\Skyrim" /v "Installed Path" | FINDSTR /R "\<.:">"%Temp%\SkyrimPath.txt"
) else (
  REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Bethesda Softworks\Skyrim" /v "Installed Path" | FINDSTR /R "\<.:">"%Temp%\SkyrimPath.txt"
)

::The "\<.:" means a line with any characters containing a colon. However key name and key type are included

:: read Skyrim path from the temporary file and save it to a variable
SET /P Skyrim=<"%Temp%\SkyrimPath.txt"

:: Remove Spaces
set TempSkyrim=%Skyrim: =%

:: Trim keyname and keytype and save Skyrim directory path
set Skyrim=%TempSkyrim:InstalledPathREG_SZ=%


:: delete the temporary file
DEL /F "%Temp%\SkyrimPath.txt"

cd \

:: detect 64 bit H/W see http://ss64.com/nt/syntax-64bit.html

IF NOT %PROCESSOR_ARCHITECTURE% == x86 (
Pushd %Skyrim:~64%
GOTO SIXTYFOUR
)
IF DEFINED PROCESSOR_ARCHITEW6432 (
Pushd %Skyrim:~64%
) else (
Pushd %Skyrim:~32%
)
:SIXTYFOUR


:: retrieved path is invalid
IF NOT %ErrorLevel%==0 (
    echo(
	ECHO I hope you saved this script in the Skyrim directory or at least a subdirectory.
	echo(
	:: script in Skyrim directory?
	IF EXIST "%~dp0\TESV.exe" (
		CD /D "%~dp0"
	) ELSE (
		:: script in Skyrim subdirectory?
		IF EXIST "%~dp0\..\TESV.exe" (
			CD /D "%~dp0\.."
		) ELSE (
			:: failed to retrieve the path of the Skyrim directory
			echo(
			ECHO Failed to retrieve the Skyrim directory.
			echo(
			GOTO Finish
		)
	)
)


:: retrieve script directory (output)


SET "Output=%Skyrim%Data\Scripts"

CD %Output%


:: retrieve script source directory (import)
SET "Import=%Output%\Source"
CD %Import%

IF [%2]==[] GOTO NOADDITIONALIMPORTS

    IF [%2]==[ADDITIONAL IMPORTS] (
	echo(
    @echo Valid import directory not specified in Notepad++ "Papyrus Compiler.bat" Command line.
	GOTO NOADDITIONALIMPORTS
    )

	SET "AdditionalImports"="%2"

SET Import=%Import%\;%AdditionalImports:~1,-1%

:NOADDITIONALIMPORTS
:: log paths
echo(
ECHO %%Skyrim%%=%Skyrim%
ECHO %%Import%%=%Import%
ECHO %%Output%%=%Output%

Popd
echo(
echo(
echo(
:: run the compiler

start "PapyrusCompiler" /B "%Skyrim%Papyrus Compiler\PapyrusCompiler.exe" %1 -f="TESV_Papyrus_Flags.flg" -import="%Import%" -output="%Output%"

:LOOP
timeout /t 1 /nobreak > nul
tasklist /fi "IMAGENAME eq PapyrusCompiler.exe" | find /i "PapyrusCompiler.exe" > nul
if errorlevel 1 goto Finish
if errorlevel 0 goto LOOP
ECHO ________________________________________________________________________________
:Finish
ECHO Press any key to exit.
PAUSE>NUL
goto :EOF

Save the script anywhere (If an error occurs move this script to the Skyrim directory or a subdirectory e. g. "\Papyrus Compiler".) and configure Notepad++ to run this:

cmd /c ""<SCRIPT DIR>\Papyrus Compiler.bat" "$(FULL_CURRENT_PATH)" "<ADDITIONAL IMPORTS>""

(Replace <SCRIPT DIR> with the path name that contains "Papyrus Compiler.bat". You can remove the second parameter which defines additional import directories but if you use it you must put this parameter in quotes for this script to work.)

Fully Integrated Compiler with NppExec (Best Choice)

The best way to integrate any compiler into Notepad++ is to use the NppExec plugin. Your compile output will appear in a window in Notepad++, you can easily copy-paste from it, it will be in color, and you can double-click on any error and it will jump you right to the line and column with the error in the editor. So, it will work like many modern IDEs do when working with compilation and errors.

The best way to use Notepad++ plugins is to to use the Plugin Manager. Unfortunately, as of Notepad++ version 7.5 and later the Plugin Manager was not shipped as part of the default plugins. At that time Notepad++ added an 64-bit build, and the Plugin Manager and many other plugins were not available for x64, so they removed it. However, that problem has since been fixed, and the Plugin Manager and many of the plugins now have x64 versions. So first, check to see if you have the 32-bit or 64-bit version of Notepad++. If it is installed in C:\Program Files (x86)\Notepad++ then you have the 32-bit. You should uninstall that and install the 64-bit version. You can download it here: https://notepad-plus-plus.org/download/v7.5.4.html (make sure to get it from the [u]Download 64-bit x64[/u] section). The latest version as of this writing is 7.5.4.

Then download and install the Plugin Manager. The latest version of of this writing is version 1.4.9. Just download the PluginManager_v1.4.9_x64.zip, and unzip it to your C:\Program Files\Notepad++. It will add one file to the plugins directory, and one file to the updater directory.

Then, launch Notepad++ and go to the Plugions->Plugin Manager->Show Plugin Manager. Find NppExec in the list and select the checkbox next to it and select Install. The latest version as of this writing was 0.5.9.9. You may need to restart Notepad++ for the Plugin to take effect.

Now, select Plugins->NppExec->Execute... or press F6. Type the following into the execute dialog box, and press Save... and save it with the name "Papyrus Compiler (Debug)". NOTE: you can also add (Release) and (Release Final) versions of this exec too by adding the -r -op and -r -op -final to the end of the last command. Adjust any of the paths here to your preference, this is for Fallout 4 in the default install location with all the DLC, and working on scripts out of the Data\Scripts\Source\User directory. NOTE: this does not require any changes to the ScriptCompile.bat file (or the others), since they is not used. This invokes the compiler directly.

npe_console -- m-
npp_save
set local fo4 = C:\Program Files (x86)\Steam\steamapps\common\Fallout 4\
set local scripts = $(fo4)\Data\Scripts
set local source = $(scripts)\Source
npp_console -
cd $(CURRENT_DIRECTORY)
npp_console +
"$(fo4)Papyrus Compiler\PapyrusCompiler.exe" "$(FILE_NAME)" -f="Institute_Papyrus_Flags.flg" -i="$(source)\user;$(source)\DLC06;$(source)\DLC05;$(source)\DLC04;$(source)\DLC03;$(source)\DLC02;$(source)\DLC01;$(source)\Base" -o="$(scripts)"

The Papyrus Compiler may require the full path/filename instead of just the filename to deal with namespaces in code:

npe_console -- m-
npp_save
set local fo4 = C:\Program Files (x86)\Steam\steamapps\common\Fallout 4\
set local papyrus = $(fo4)\Papyrus Compiler\PapyrusCompiler.exe
set local scripts = $(fo4)\Data\Scripts
set local source = $(scripts)\Source
set local include = $(source)\user;$(source)\base;$(source)
"$(papyrus)" "$(CURRENT_DIRECTORY)\$(FILE_NAME)" -f="Institute_Papyrus_Flags.flg" -i="$(include)" -o="$(scripts)"

The select Plugins->NppExec->Console Output Filters... and set them up with these values as a place to start, then customize to your liking:

%FILE%(%LINE%,%CHAR%)* 0xC0 0x00 0x00
Compiling "*"* 0x00 0x00 0xC0
No output generated for* 0xA0 0x00 0x00
Compilation succeeded. 0x00 0xA0 0x00

And finally, setup the menu item and keyboard shortcut: Plugins->NppExec->Advanced Options... and find the Menu Item section (bottom left of the dialog), give the Menu Item a name "Papyrus Compiler (Debug)" and select the script "Papyrus Compiler (Debug)". Click Add/Modify and it will tell you to restart Notepad++ for the change to take effect, so do that. Now you will have a new menu item Plugins->NppExec->Papyrus Compiler (Debug). To bind a shortcut key to that, go to Settings->Shortcut Mapper...->Plugin Commands->Papyrus Compiler (Debug) and select a shortcut. I use Ctrl-F9 since I've been doing a lot of xEdit Scripting in Object Pascal using Delphi, and that's Delphi's default compile key. But use whatever key you'd like, Notepad++ will tell you if there is a conflict.

In the end, it should look like this:

 

Setting up Papyrus Language Definitions

Notepad++ supports both autocomplete and syntax highlighting for custom language. The following two sections describe the steps you need to take to enable each of these features for Papyrus.

Autocomplete

  1. Open up Notepad++
  2. Copy the content from this page into a new file: Papyrus Autocomplete Language Definitions
  3. Save the new file as papyrus.xml in your Notepad++\plugins\APIs directory (for example, C:\Program Files (x86)\Notepad++\plugins\APIs)
  4. In the Backup/Auto-Completion tab of the Preferences window of Notepad++ (under Settings), tick the "Enable auto-completion on each input" and configure the feature to work how you want.
    Currently, a portion of the functions have parameter information defined, so if you tick "Function parameters hint on input" you will see more information when typing these functions.

Syntax Highlighting

  1. Create an XML file with the following content (you can call it whatever you like and save it anywhere you like):
    <NotepadPlus>
        <UserLang name="Papyrus" ext="psc">
            <Settings>
                <Global caseIgnored="yes" />
                <TreatAsSymbol comment="yes" commentLine="yes" />
                <Prefix words1="no" words2="no" words3="no" words4="no" />
            </Settings>
            <KeywordLists>
                <Keywords name="Delimiters">&quot;00&quot;00</Keywords>
                <Keywords name="Folder+">Event Function If State While</Keywords>
                <Keywords name="Folder-">EndEvent EndFunction EndIf EndState EndWhile Native</Keywords>
                <Keywords name="Operators">- ! % &amp; ( ) * , . / [ ] | + &lt; = &gt;</Keywords>
                <Keywords name="Comment">1{ 2} 0;</Keywords>
                <Keywords name="Words1">abs acos Activate Add AddAchievement AddDependentAnimatedObjectReference AddForm AddHavokBallAndSocketConstraint AddInventoryEventFilter AddItem AddPerk AddShout AddSpell AddToFaction AddToMap AdvanceSkill AllowBleedoutDialogue AllowPCDialogue Apply ApplyCrossFade ApplyHavokImpulse asin atan AttachAshPile BlockActivation CalculateEncounterLevel CalculateFavorCost CanFastTravelToMarker CanPayCrimeGold CaptureFrameRate Cast Ceiling CenterOnCell CenterOnCellAndWait Clear ClearArrested ClearDestruction ClearExtraArrows ClearForcedMovement ClearKeepOffsetFromActor ClearLookAt ClearPrison ClearTempEffects CloseUserLog CompleteAllObjectives CompleteQuest cos CreateDetectionEvent DamageActorValue DamageAV DamageObject DBSendPlayerPosition DebugChannelNotify DegreesToRadians Delete DeleteWhenAble Disable DisableNoWait DisablePlayerControls Dispel DispelAllSpells DispelSpell DoCombatSpellApply DropObject DumpAliasData Enable EnableAI ENableFastTravel EnableFastTravel EnableNoWait EnablePlayerControls EndFrameRateCapture EquipItem EquipShout EquipSpell EvaluatePackage FadeOutGame FailAllObjectives FastTravel FindClosestActor FindClosestReferenceOfAnyTypeInList FindClosestReferenceOfType FindRandomActor FindRandomReferenceOfAnyTypeInList FindRandomReferenceOfType FindWeather Fire Floor ForceActive ForceActorValue ForceAddRagdollToWorld ForceAV ForceFirstPerson ForceLocationTo ForceMovementDirection ForceMovementDirectionRamp ForceMovementRotationSpeed ForceMovementRotationSpeedRamp ForceMovementSpeed ForceMovementSpeedRamp ForceRefTo ForceRemoveRagdollFromWorld ForceStart ForceTargetAngle ForceTargetDirection ForceTargetSpeed ForceThirdPerson GameTimeToString Get GetActorBase GetActorOwner GetActorReference GetActorValue GetActorValuePercentage GetAlias GetAngleX GetAngleY GetAngleZ GetAnimationVariableBool GetAnimationVariableFloat GetAnimationVariableInt GetAssociatedSkill GetAt GetAV GetAverageFrameRate GetAVPercentage GetBaseActorValue GetBaseAV GetBaseObject GetBribeAmount GetBudgetCount GetBudgetName GetCasterActor GetClass GetClassification GetCombatState GetCombatTarget GetConfigName GetCrimeFaction GetCrimeGold GetCrimeGoldNonViolent GetCrimeGoldViolent GetCurrentBudget GetCurrentDestructionStage GetCurrentGameTime GetCurrentLocation GetCurrentMemory GetCurrentPackage GetCurrentRealTime GetCurrentScene GetCurrentStageID GetCurrentWeather GetCurrentWeatherTransition GetDeadCount GetDialogueTarget GetDistance GetEditorLocation GetEquippedItemType GetEquippedShield GetEquippedShout GetEquippedSpell GetEquippedWeapon GetFactionOwner GetFactionRank GetFactionReaction GetFavorPoints GetFlyingState GetForcedLandingMarker GetForm GetFormID GetGameSettingFloat GetGameSettingInt GetGameSettingString GetGiftFilter GetGoldAmount GetGoldValue GetHeadingAngle GetHeight GetHigestRelationshipRank GetHighestRelationshipRank GetInfamy GetInfamyNonViolent GetInfamyViolent GetItemCount GetItemHealthPercent GetKey GetKeywordData GetKiller GetLength GetLevel GetLeveledActorBase GetLightLevel GetLinkedRef GetLocation GetLockLevel GetLowestRelationshipRank GetMass GetMaxFrameRate GetMinFrameRate GetNoBleedoutRecovery GetNthLinkedRef GetOpenState GetOutgoingWeather GetOwningQuest GetParentCell GetPlatformName GetPlayer GetPlayerControls GetPlayerGrabbedRef GetPlayersLastRiddenHorse GetPositionX GetPositionY GetPositionZ GetRace GetReaction GetRealHoursPassed GetRef GetReference GetRefTypeAliveCount GetRefTypeDeadCount GetRegard GetRelationshipRank GetReputation GetScale GetSex GetSitState GetSize GetSkyMode GetSleepState GetStage GetStageDone GetState GetStolenItemValueCrime GetStolenItemValueNoCrime GetTargetActor GetTemplate GetTriggerObjectCount GetValue GetValueInt GetVersionNumber GetVoiceRecoveryTime GetVoiceType GetWidth GetWorldSpace GoToState GtLockLevel HasAssociation HasCommonParent HasEffectKeyword HasFamilyRelationship HasForm HasKeyword HasLOS HasMagicEffect HasMagicEffectWithKeyword HasNode HasParentRelationship HasPerk HasRefType HasSpell HideTitleSequenceMenu IgnoreFriendlyHits IncrementSkill IncrementSkillBy IncrementStat InterruptCast Is3DLoaded IsActionComplete IsActivateChild IsActivateControlsEnabled IsActivationBlocked IsActive IsAlarmed IsAlerted IsAllowedToFly IsArrested IsArrestingTarget IsAttached IsBleedingOut IsBribed IsCamSwitchControlsEnabled IsChild IsCleared IsCommandedActor IsCompleted IsDead IsDetectedBy IsDisabled IsDoingFavor IsEquipped IsEssential IsEuiped IsFactionInCrimeGroup IsFastTravelEnabled IsFightingControlsEnabled IsFlying IsFurnitureInUse IsFurnitureMarkerInUse IsGhost IsGuard IsHostile IsHostileToActor IsIgnoringFriendlyHits IsInCombat IsInDialogueWithPlayer IsInFaction IsInInterior IsInKillMove IsInMenuMode IsInterior IsIntimidated IsInvulnerable IsJournalControlsEnabled IsLoaded IsLockBroken IsLocked IsLookingControlsEnabled IsMapMarkerVisible IsMenuControlsEnabled IsMovementControlsEnabled IsObjectiveCompleted IsObjectiveDisplayed IsObjectiveFailed IsPlayerExpelled IsPlayersLastRiddenHorse IsPlayerTeammate IsPlaying IsProtected IsRunning IsSameLocation IsSneaking IsSneakingControlsEnabled IsSprinting IsStageDone IsStartin IsStarting IsStopped IsStopping IsTrespassing IsUnconscious IsUnique IsWeaponDrawn IsWordUnlocked KeepOffsetFromActor Kill KillSilent KnockAreaEffect LearnAllEffects LearnEffect LearnNextEffect Lock MessageBox ModActorValue ModAV ModCrimeGold ModFactionRank ModFavorPoints ModFavorPointsWithGlobal ModReaction ModRegard MoveTo MoveToInteractionLocation MoveToMyEditorLocation MoveToNode MoveToPackageLocation MoveToWhenUnloaded Mute Notification OpenInventory OpenUserLog OverBudget PathToReference Pause PlaceActorAtMe PlaceAtMe Play PlayAndWait PlayAnimation PlayAnimationAndWait PlayerKnows PlayerMoveToAndWait PlayerPayCrimeGold PlayGamebryoAnimation PlayIdle PlayIdleWithTarget PlayImpactEffect PlaySubGraphAnimation PlaySyncedAnimationAndWaitSS PlaySyncedAnimationSS PlayTerrainEffect PopTo pow PrecacheCharGen PrecacheCharGenClear ProcessTrapHit PushActorAway QueryStat QuitGame QuitToMainMenu RadiansToDegrees RandomFloat RandomInt RegisterForAnimationEvent RegisterForLOS RegisterForSingleLOSGain RegisterForSingleLOSLost RegisterForSingleUpdate RegisterForSingleUpdateGameTime RegisterForSleep RegisterForTrackedStatsEvent RegisterForUpdate RegisterForUpdateGameTime ReleaseOverride RemoteCast Remove RemoveAddedForm RemoveAllInventoryEventFilters RemoveAllItems RemoveCrossFade RemoveDependentAnimatedObjectReference RemoveFromAllFactions RemoveFromFaction RemoveHavokConstraints RemoveInventoryEventFilter RemoveItem RemovePerk RemoveShout RemoveSpell RequestAutoSave RequestModel RequestSave Reset ResetHealthAndLimbs ResetHelpMessage RestoreActorValue RestoreAV Resurrect Revert Say SendAnimationEvent SendAssaultAlarm SendPlayerToJail SendStealAlarm SendStoryEvent SendStoryEventAndWait SendTrespassAlarm SendWereWolfTransformation ServeTime Set SetActive SetActorCause SetActorOwner SetActorValue SetAlert SetAllowFlying SetAlly SetAlpha SetAngle SetAnimationVariableBool SetAnimationVariableFloat SetAnimationVariableInt SetAttackActorOnSight SetAV SetBeastForm SetBribed SetCameraTarget SetCleared SetCrimeFaction SetCrimeGold SetCrimeGoldViolent SetCriticalStage SetCurrentStageID SetDestroyed SetDoingFavor SetEnemy SetEssential SetFactionOwner SetFactionRank SetFogPlanes SetFogPower SetFootIK SetForcedLandingMarker SetFrequency SetGhost SetGodMode SetHeadTracking SetHudCartMode SetInChargen SetINIBool SetINIFloat SetINIInt SetINIString SetInstanceVolume SetIntimidated SetInvulnerable SetKeywordData SetLockLevel SetLookAt SetMotionType SetNoBleedoutRecovery SetNoFavorAllowed SetNotShowOnStealthMeter SetObjectiveCompleted SetObjectiveDisplayed SetObjectiveFailed SetOpen SetOutfit SetPlayerAIDriven SetPlayerControls SetPlayerEnemy SetPlayerExpelled SetPlayerReportCrime SetPlayerResistingArrest SetPlayerTeammate SetPosition SetProtected SetPublic SetRace SetRaction SetReaction SetRelationshipRank SetRestrained SetScale SetSittingRotation SetStage SetUnconscious SetValue SetValueInt SetVehicle SetVoiceRecoveryTime SetVolume ShakeCamera ShakeController Show ShowAsHelpMessage ShowBarterMenu ShowFirstPersonGeometry ShowGiftMenu ShowRaceMenu ShowRefPosition ShowTitleSequenceMenu ShowTrainingMenu sin SplineTranslateTo SplineTranslateToRefNode sqrt Start StartCannibal StartCombat StartFrameRateCapture StartObjectProfiling StartScriptProfiling StartStackProfiling StartTitleSequence StartVampireFeed Stop StopCombat StopCombatAlarm StopInstance StopObjectProfiling StopScriptProfiling StopStackProfiling StopTranslation TakeScreenshot tan TeachWord TetherToHorse ToggleAI ToggleCollisions ToggleMenus Trace TraceConditional TraceStack TraceUser TranslateTo TrapSoul TriggerScreenBlood TryToEnable TryToAddToFaction TryToDisable TryToEvaluatePackage TryToKill TryToMoveTo TryToRemoveFromFaction TryToReset TryToStopCombat UnequipAll UnEquipItem UnequipItem UnequipShout UnequipSpell UnLockOwnedDoorsInCell UnlockWord UnMute UnPause UnregisterForAnimationEvent UnregisterForLOS UnregisterForSleep UnregisterForTrackedStatsEvent UnregisterForUpdate UnregisterForUpdateGameTime UpdateCurrentInstanceGlobal UsingGamepad Wait WaitForAnimationEvent WaitGameTime WaitMenuMode WillIntimidateSucceed WornHasKeyword</Keywords>
                <Keywords name="Words2">OnActivate OnAnimationEvent OnAttachedToCell OnBeginState OnCellAttach OnCellDetach OnCellLoad OnClose OnCombatStateChanged OnContainerChanged OnDeath OnDying OnDestructionStageChanged OnDetachedFromCell OnEffectFinish OnEffectStart OnEndState OnEnterBleedout OnEquipped OnGainLOS OnGetUp OnGrab OnHit OnInit OnItemAdded OnItemRemoved OnLoad OnLocationChange OnLockStateChanged OnLostLOS OnMagicEffectApply OnObjectEquipped OnObjectUnequipped OnOpen OnPackageChange OnPackageEnd OnPackageStart OnRaceSwitchComplete OnRead OnRelease OnReset OnSell OnSleepStart OnSleepStop OnStoryActivateActor OnStoryAddToPlayer OnStoryArrest OnStoryAssaultActor OnStoryBribeNPC OnStoryCastMagic OnStoryChangeLocation OnStoryCraftItem OnStoryCrimeGold OnStoryCure OnStoryDialogue OnStoryDiscoverDeadBody OnStoryEscapeJail OnStoryFlatterNPC OnStoryHello OnStoryIncreaseLevel OnStoryIncreaseSkill OnStoryInfection OnStoryIntimidateNPC OnStoryJail OnStoryKillActor OnStoryNewVoicePower OnStoryPayFine OnStoryPickLock OnStoryPlayerGetsFavor OnStoryRelationshipChange OnStoryRemoveFromPlayer OnStoryScript OnStoryServedTime OnStoryTrespass OnTrackedStatsEvent OnTranslationAlmostComplete OnTranslationComplete OnTranslationFailed OnTrapHit OnTrapHitStart OnTrapHitStop OnTrigger OnTriggerEnter OnTriggerLeave OnUnequipped OnUnload OnUpdate OnUpdateGameTime OnWardHit</Keywords>
                <Keywords name="Words3">Action Activator ActiveMagicEffect Actor ActorBase Alias Ammo Apparatus Armor AssociationType Book Cell Class ConstructibleObject Container Debug Door EffectShader Enchantment EncounterZone Explosion Faction Flora Form FormList Furniture Game GlobalVariable Hazard Idle ImageSpaceModifier ImpactDataSet Ingredient Key Keyword LeveledActor LeveledItem LeveledSpell Light Location LocationAlias LocationRefType MagicEffect Math Message MiscObject MusicType ObjectReference Outfit Package Perk Potion Projectile Quest Race ReferenceAlias Scene Scroll Shout SoulGem Sound SoundCategory Spell Static TalkingActivator Topic TopicInfo Utility VisualEffect VoiceType Weapon Weather WordOfPower WorldSpace</Keywords>
                <Keywords name="Words4">As Auto AutoReadOnly Bool Conditional Debug Else ElseIf EndProperty Extends False Float Game Global Hidden Import Int Length New None Parent Property Return ScriptName Self String True Utility</Keywords>
            </KeywordLists>
            <Styles>
                <WordsStyle name="DEFAULT" styleID="11" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" />
                <WordsStyle name="FOLDEROPEN" styleID="12" fgColor="0000FF" bgColor="FFFFFF" fontName="" fontStyle="1" />
                <WordsStyle name="FOLDERCLOSE" styleID="13" fgColor="0000FF" bgColor="FFFFFF" fontName="" fontStyle="1" />
                <WordsStyle name="KEYWORD1" styleID="5" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="1" />
                <WordsStyle name="KEYWORD2" styleID="6" fgColor="800000" bgColor="FFFFFF" fontName="" fontStyle="1" />
                <WordsStyle name="KEYWORD3" styleID="7" fgColor="008000" bgColor="FFFFFF" fontName="" fontStyle="1" />
                <WordsStyle name="KEYWORD4" styleID="8" fgColor="0000FF" bgColor="FFFFFF" fontName="" fontStyle="1" />
                <WordsStyle name="COMMENT" styleID="1" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="3" />
                <WordsStyle name="COMMENT LINE" styleID="2" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="2" />
                <WordsStyle name="NUMBER" styleID="4" fgColor="0000FF" bgColor="FFFFFF" fontName="" fontStyle="0" />
                <WordsStyle name="OPERATOR" styleID="10" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="1" />
                <WordsStyle name="DELIMINER1" styleID="14" fgColor="000000" bgColor="FFFF00" fontName="" fontStyle="2" />
                <WordsStyle name="DELIMINER2" styleID="15" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" />
                <WordsStyle name="DELIMINER3" styleID="16" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" />
            </Styles>
        </UserLang>
    </NotepadPlus>
    
  2. Open Notepad++
  3. Open the "User Defined Language" window via Language -> Define Your Language...
  4. Select "Import..."
  5. Select the XML file you created earlier.
  6. If the import was successful, you should see a notification saying "Import successful."

Now, when you open up Papyrus source files (with the extension .psc) Notepad++ will automatically highlight them for you.

If you are creating your own script from scratch, you'll need to select the language manually. "Papyrus" should be available near the bottom of the Language menu in Notepad++.

Darker Syntax Highlighting

If the above is too bright for your eyes then you can try a darker approach which can be found here User:PROXiCiDE/Notepad++_Dark.xml

An updated version of the above can be found here User:SilentSpike/Notepad++_Dark.xml

More Default Syntax Highlighting

If you prefer syntax highlighting that fits better in the default colors used by Notepad++ you can find an alternative at User:Schnusch/Notepad++/Syntax Highlighting.

Fixed Syntax Highlighting for Notepad++ v6.4

This alternative highlighting is compatible with Notepad++ v6.4 and corrects several bugs in the above:

  • hexadecimal literals (i.e. "0x1") are now recognized correctly
  • foldable blocks ("If", "Function", etc.) are now handled correctly, without misidentifying middles of words (i.e. the "if" in "notification")
  • full properties ("Property ... EndProperty") are now also foldable
  • non-documentation block comments (";/ ... /;") are now recognized correctly
  • the escape character in strings ("this \"is\" all one string") is now handled correctly
  • highlight colors match those used in code examples on this wiki
<NotepadPlus>
    <UserLang name="Papyrus" ext="psc" udlVersion="2.1">
        <Settings>
            <Global caseIgnored="yes" allowFoldOfComments="no" foldCompact="no" forcePureLC="0" decimalSeparator="0" />
            <Prefix Keywords1="no" Keywords2="no" Keywords3="no" Keywords4="no" Keywords5="no" Keywords6="no" Keywords7="no" Keywords8="no" />
        </Settings>
        <KeywordLists>
            <Keywords name="Comments">00 01 02 03 04</Keywords>
            <Keywords name="Numbers, prefix1">0x</Keywords>
            <Keywords name="Numbers, prefix2"></Keywords>
            <Keywords name="Numbers, extras1"></Keywords>
            <Keywords name="Numbers, extras2"></Keywords>
            <Keywords name="Numbers, suffix1"></Keywords>
            <Keywords name="Numbers, suffix2"></Keywords>
            <Keywords name="Numbers, range"></Keywords>
            <Keywords name="Operators1">( ) [ ] , = + - * / % . ! &gt; &lt; | &amp;</Keywords>
            <Keywords name="Operators2">as</Keywords>
            <Keywords name="Folders in code1, open"></Keywords>
            <Keywords name="Folders in code1, middle"></Keywords>
            <Keywords name="Folders in code1, close"></Keywords>
            <Keywords name="Folders in code2, open">Event Function If Property State While</Keywords>
            <Keywords name="Folders in code2, middle">ElseIf Else</Keywords>
            <Keywords name="Folders in code2, close">Auto AutoReadOnly EndEvent EndFunction EndIf EndProperty EndState EndWhile</Keywords>
            <Keywords name="Folders in comment, open"></Keywords>
            <Keywords name="Folders in comment, middle"></Keywords>
            <Keywords name="Folders in comment, close"></Keywords>
            <Keywords name="Keywords1">As Auto AutoReadOnly Conditional Else ElseIf EndEvent EndFunction EndIf EndProperty EndState EndWhile Event Extends False Function Global Hidden If Import Length Native New None Parent Property Return ScriptName Self State True While</Keywords>
            <Keywords name="Keywords2">Bool Float Int String</Keywords>
            <Keywords name="Keywords3">Action Activator ActiveMagicEffect Actor ActorBase Alias Ammo Apparatus Armor AssociationType Book Cell Class ConstructibleObject Container Debug Door EffectShader Enchantment EncounterZone Explosion Faction Flora Form FormList Furniture Game GlobalVariable Hazard Idle ImageSpaceModifier ImpactDataSet Ingredient Key Keyword LeveledActor LeveledItem LeveledSpell Light Location LocationAlias LocationRefType MagicEffect Math Message MiscObject MusicType ObjectReference Outfit Package Perk Potion Projectile Quest Race ReferenceAlias Scene Scroll Shout SoulGem Sound SoundCategory Spell Static TalkingActivator Topic TopicInfo Utility VisualEffect VoiceType Weapon Weather WordOfPower WorldSpace</Keywords>
            <Keywords name="Keywords4">abs acos Activate Add AddAchievement AddDependentAnimatedObjectReference AddForm AddHavokBallAndSocketConstraint AddInventoryEventFilter AddItem AddPerk AddShout AddSpell AddToFaction AddToMap AdvanceSkill AllowBleedoutDialogue AllowPCDialogue Apply ApplyCrossFade ApplyHavokImpulse asin atan AttachAshPile BlockActivation CalculateEncounterLevel CalculateFavorCost CanFastTravelToMarker CanPayCrimeGold CaptureFrameRate Cast Ceiling CenterOnCell CenterOnCellAndWait Clear ClearArrested ClearDestruction ClearExtraArrows ClearForcedMovement ClearKeepOffsetFromActor ClearLookAt ClearPrison ClearTempEffects CloseUserLog CompleteAllObjectives CompleteQuest cos CreateDetectionEvent DamageActorValue DamageAV DamageObject DBSendPlayerPosition DebugChannelNotify DegreesToRadians Delete DeleteWhenAble Disable DisableNoWait DisablePlayerControls Dispel DispelAllSpells DispelSpell DoCombatSpellApply DropObject DumpAliasData Enable EnableAI ENableFastTravel EnableFastTravel EnableNoWait EnablePlayerControls EndFrameRateCapture EquipItem EquipShout EquipSpell EvaluatePackage FadeOutGame FailAllObjectives FastTravel FindClosestActor FindClosestReferenceOfAnyTypeInList FindClosestReferenceOfType FindRandomActor FindRandomReferenceOfAnyTypeInList FindRandomReferenceOfType FindWeather Fire Floor ForceActive ForceActorValue ForceAddRagdollToWorld ForceAV ForceFirstPerson ForceLocationTo ForceMovementDirection ForceMovementDirectionRamp ForceMovementRotationSpeed ForceMovementRotationSpeedRamp ForceMovementSpeed ForceMovementSpeedRamp ForceRefTo ForceRemoveRagdollFromWorld ForceStart ForceTargetAngle ForceTargetDirection ForceTargetSpeed ForceThirdPerson GameTimeToString Get GetActorBase GetActorOwner GetActorReference GetActorValue GetActorValuePercentage GetAlias GetAngleX GetAngleY GetAngleZ GetAnimationVariableBool GetAnimationVariableFloat GetAnimationVariableInt GetAssociatedSkill GetAt GetAV GetAverageFrameRate GetAVPercentage GetBaseActorValue GetBaseAV GetBaseObject GetBribeAmount GetBudgetCount GetBudgetName GetCasterActor GetClass GetClassification GetCombatState GetCombatTarget GetConfigName GetCrimeFaction GetCrimeGold GetCrimeGoldNonViolent GetCrimeGoldViolent GetCurrentBudget GetCurrentDestructionStage GetCurrentGameTime GetCurrentLocation GetCurrentMemory GetCurrentPackage GetCurrentRealTime GetCurrentScene GetCurrentStageID GetCurrentWeather GetCurrentWeatherTransition GetDeadCount GetDialogueTarget GetDistance GetEditorLocation GetEquippedItemType GetEquippedShield GetEquippedShout GetEquippedSpell GetEquippedWeapon GetFactionOwner GetFactionRank GetFactionReaction GetFavorPoints GetFlyingState GetForcedLandingMarker GetForm GetFormID GetGameSettingFloat GetGameSettingInt GetGameSettingString GetGiftFilter GetGoldAmount GetGoldValue GetHeadingAngle GetHeight GetHigestRelationshipRank GetHighestRelationshipRank GetInfamy GetInfamyNonViolent GetInfamyViolent GetItemCount GetItemHealthPercent GetKey GetKeywordData GetKiller GetLength GetLevel GetLeveledActorBase GetLightLevel GetLinkedRef GetLocation GetLockLevel GetLowestRelationshipRank GetMass GetMaxFrameRate GetMinFrameRate GetNoBleedoutRecovery GetNthLinkedRef GetOpenState GetOutgoingWeather GetOwningQuest GetParentCell GetPlatformName GetPlayer GetPlayerControls GetPlayerGrabbedRef GetPlayersLastRiddenHorse GetPositionX GetPositionY GetPositionZ GetRace GetReaction GetRealHoursPassed GetReference GetRefTypeAliveCount GetRefTypeDeadCount GetRegard GetRelationshipRank GetReputation GetScale GetSex GetSitState GetSize GetSkyMode GetSleepState GetStage GetStageDone GetState GetStolenItemValueCrime GetStolenItemValueNoCrime GetTargetActor GetTemplate GetTriggerObjectCount GetValue GetVersionNumber GetVoiceRecoveryTime GetVoiceType GetWidth GetWorldSpace GoToState GtLockLevel HasAssociation HasCommonParent HasEffectKeyword HasFamilyRelationship HasForm HasKeyword HasLOS HasMagicEffect HasMagicEffectWithKeyword HasNode HasParentRelationship HasPerk HasRefType HasSpell HideTitleSequenceMenu IgnoreFriendlyHits IncrementSkill IncrementSkillBy IncrementStat InterruptCast Is3DLoaded IsActionComplete IsActivateChild IsActivateControlsEnabled IsActivationBlocked IsActive IsAlarmed IsAlerted IsAllowedToFly IsArrested IsArrestingTarget IsAttached IsBleedingOut IsBribed IsCamSwitchControlsEnabled IsChild IsCleared IsCommandedActor IsCompleted IsDead IsDetectedBy IsDisabled IsDoingFavor IsEquipped IsEssential IsEuiped IsFactionInCrimeGroup IsFastTravelEnabled IsFightingControlsEnabled IsFlying IsFurnitureInUse IsFurnitureMarkerInUse IsGhost IsGuard IsHostile IsHostileToActor IsIgnoringFriendlyHits IsInCombat IsInDialogueWithPlayer IsInFaction IsInInterior IsInKillMove IsInMenuMode IsInterior IsIntimidated IsInvulnerable IsJournalControlsEnabled IsLoaded IsLockBroken IsLocked IsLookingControlsEnabled IsMapMarkerVisible IsMenuControlsEnabled IsMovementControlsEnabled IsObjectiveCompleted IsObjectiveDisplayed IsObjectiveFailed IsPlayerExpelled IsPlayersLastRiddenHorse IsPlayerTeammate IsPlaying IsProtected IsRunning IsSameLocation IsSneaking IsSneakingControlsEnabled IsSprinting IsStageDone IsStartin IsStarting IsStopped IsStopping IsTrespassing IsUnconscious IsUnique IsWeaponDrawn IsWordUnlocked KeepOffsetFromActor Kill KillSilent KnockAreaEffect LearnAllEffects LearnEffect LearnNextEffect Lock MessageBox ModActorValue ModAV ModCrimeGold ModFactionRank ModFavorPoints ModFavorPointsWithGlobal ModReaction ModRegard MoveTo MoveToInteractionLocation MoveToMyEditorLocation MoveToNode MoveToPackageLocation MoveToWhenUnloaded Mute Notification OpenInventory OpenUserLog OverBudget PathToReference Pause PlaceActorAtMe PlaceAtMe Play PlayAndWait PlayAnimation PlayAnimationAndWait PlayerKnows PlayerMoveToAndWait PlayerPayCrimeGold PlayGamebryoAnimation PlayIdle PlayIdleWithTarget PlayImpactEffect PlaySubGraphAnimation PlaySyncedAnimationAndWaitSS PlaySyncedAnimationSS PlayTerrainEffect PopTo pow PrecacheCharGen PrecacheCharGenClear ProcessTrapHit PushActorAway QueryStat QuitGame QuitToMainMenu RadiansToDegrees RandomFloat RandomInt RegisterForAnimationEvent RegisterForLOS RegisterForSingleLOSGain RegisterForSingleLOSLost RegisterForSingleUpdate RegisterForSingleUpdateGameTime RegisterForSleep RegisterForTrackedStatsEvent RegisterForUpdate RegisterForUpdateGameTime ReleaseOverride RemoteCast Remove RemoveAddedForm RemoveAllInventoryEventFilters RemoveAllItems RemoveCrossFade RemoveDependentAnimatedObjectReference RemoveFromAllFactions RemoveFromFaction RemoveHavokConstraints RemoveInventoryEventFilter RemoveItem RemovePerk RemoveShout RemoveSpell RequestAutoSave RequestModel RequestSave Reset ResetHealthAndLimbs ResetHelpMessage RestoreActorValue RestoreAV Resurrect Revert Say SendAnimationEvent SendAssaultAlarm SendPlayerToJail SendStealAlarm SendStoryEvent SendStoryEventAndWait SendTrespassAlarm SendWereWolfTransformation ServeTime Set SetActive SetActorCause SetActorOwner SetActorValue SetAlert SetAllowFlying SetAlly SetAlpha SetAngle SetAnimationVariableBool SetAnimationVariableFloat SetAnimationVariableInt SetAttackActorOnSight SetAV SetBeastForm SetBribed SetCameraTarget SetCleared SetCrimeFaction SetCrimeGold SetCrimeGoldViolent SetCriticalStage SetCurrentStageID SetDestroyed SetDoingFavor SetEnemy SetEssential SetFactionOwner SetFactionRank SetFogPlanes SetFogPower SetFootIK SetForcedLandingMarker SetFrequency SetGhost SetGodMode SetHeadTracking SetHudCartMode SetInChargen SetINIBool SetINIFloat SetINIInt SetINIString SetInstanceVolume SetIntimidated SetInvulnerable SetKeywordData SetLockLevel SetLookAt SetMotionType SetNoBleedoutRecovery SetNoFavorAllowed SetNotShowOnStealthMeter SetObjectiveCompleted SetObjectiveDisplayed SetObjectiveFailed SetOpen SetOutfit SetPlayerAIDriven SetPlayerControls SetPlayerEnemy SetPlayerExpelled SetPlayerReportCrime SetPlayerResistingArrest SetPlayerTeammate SetPosition SetProtected SetPublic SetRace SetRaction SetReaction SetRelationshipRank SetRestrained SetScale SetSittingRotation SetStage SetUnconscious SetValue SetVehicle SetVoiceRecoveryTime SetVolume ShakeCamera ShakeController Show ShowAsHelpMessage ShowBarterMenu ShowFirstPersonGeometry ShowGiftMenu ShowRaceMenu ShowRefPosition ShowTitleSequenceMenu ShowTrainingMenu sin SplineTranslateTo SplineTranslateToRefNode sqrt Start StartCannibal StartCombat StartFrameRateCapture StartObjectProfiling StartScriptProfiling StartStackProfiling StartTitleSequence StartVampireFeed Stop StopCombat StopCombatAlarm StopInstance StopObjectProfiling StopScriptProfiling StopStackProfiling StopTranslation TakeScreenshot tan TeachWord TetherToHorse ToggleAI ToggleCollisions ToggleMenus Trace TraceConditional TraceStack TraceUser TranslateTo TrapSoul TriggerScreenBlood TryoEnable TryToAddToFaction TryToDisable TryToKill TryToMoveTo TryToRemoveFromFaction TryToReset TryToStopCombat UnequipAll UnEquipItem UnequipItem UnequipShout UnequipSpell UnLockOwnedDoorsInCell UnlockWord UnMute UnPause UnregisterForAnimationEvent UnregisterForLOS UnregisterForSleep UnregisterForTrackedStatsEvent UnregisterForUpdate UnregisterForUpdateGameTime UpdateCurrentInstanceGlobal UsingGamepad Wait WaitForAnimationEvent WaitGameTime WaitMenuMode WillIntimidateSucceed WornHasKeyword</Keywords>
            <Keywords name="Keywords5">OnActivate OnAnimationEvent OnAttachedToCell OnBeginState OnCellAttach OnCellDetach OnCellLoad OnClose OnCombatStateChanged OnContainerChanged OnDeath OnDying OnDestructionStageChanged OnDetachedFromCell OnEffectFinish OnEffectStart OnEndState OnEnterBleedout OnEquipped OnGainLOS OnGetUp OnGrab OnHit OnInit OnItemAdded OnItemRemoved OnLoad OnLocationChange OnLockStateChanged OnLostLOS OnMagicEffectApply OnObjectEquipped OnObjectUnequipped OnOpen OnPackageChange OnPackageEnd OnPackageStart OnRaceSwitchComplete OnRead OnRelease OnReset OnSell OnSleepStart OnSleepStop OnStoryActivateActor OnStoryAddToPlayer OnStoryArrest OnStoryAssaultActor OnStoryBribeNPC OnStoryCastMagic OnStoryChangeLocation OnStoryCraftItem OnStoryCrimeGold OnStoryCure OnStoryDialogue OnStoryDiscoverDeadBody OnStoryEscapeJail OnStoryFlatterNPC OnStoryHello OnStoryIncreaseLevel OnStoryIncreaseSkill OnStoryInfection OnStoryIntimidateNPC OnStoryJail OnStoryKillActor OnStoryNewVoicePower OnStoryPayFine OnStoryPickLock OnStoryPlayerGetsFavor OnStoryRelationshipChange OnStoryRemoveFromPlayer OnStoryScript OnStoryServedTime OnStoryTrespass OnTrackedStatsEvent OnTranslationAlmostComplete OnTranslationComplete OnTranslationFailed OnTrapHit OnTrapHitStart OnTrapHitStop OnTrigger OnTriggerEnter OnTriggerLeave OnUnequipped OnUnload OnUpdate OnUpdateGameTime OnWardHit</Keywords>
            <Keywords name="Keywords6"></Keywords>
            <Keywords name="Keywords7"></Keywords>
            <Keywords name="Keywords8"></Keywords>
            <Keywords name="Delimiters">00;/ 01 02/; 03{ 04 05} 06; 07 08((EOL)) 09&quot; 10\ 11&quot; 12 13 14 15 16 17 18 19 20 21 22 23</Keywords>
        </KeywordLists>
        <Styles>
            <WordsStyle name="DEFAULT" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
            <WordsStyle name="COMMENTS" fgColor="8E8E8E" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
            <WordsStyle name="LINE COMMENTS" fgColor="8E8E8E" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
            <WordsStyle name="NUMBERS" fgColor="FF0080" bgColor="FFFFFF" fontName="" fontStyle="1" nesting="0" />
            <WordsStyle name="KEYWORDS1" fgColor="0000FF" bgColor="FFFFFF" fontName="" fontStyle="1" nesting="0" />
            <WordsStyle name="KEYWORDS2" fgColor="008040" bgColor="FFFFFF" fontName="" fontStyle="1" nesting="0" />
            <WordsStyle name="KEYWORDS3" fgColor="008040" bgColor="FFFFFF" fontName="" fontStyle="1" nesting="0" />
            <WordsStyle name="KEYWORDS4" fgColor="6565C6" bgColor="FFFFFF" fontName="" fontStyle="1" nesting="0" />
            <WordsStyle name="KEYWORDS5" fgColor="6565C6" bgColor="FFFFFF" fontName="" fontStyle="1" nesting="0" />
            <WordsStyle name="KEYWORDS6" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
            <WordsStyle name="KEYWORDS7" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
            <WordsStyle name="KEYWORDS8" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
            <WordsStyle name="OPERATORS" fgColor="0080FF" bgColor="FFFFFF" fontName="" fontStyle="1" nesting="0" />
            <WordsStyle name="FOLDER IN CODE1" fgColor="0000FF" bgColor="FFFFFF" fontName="" fontStyle="1" nesting="0" />
            <WordsStyle name="FOLDER IN CODE2" fgColor="0000FF" bgColor="FFFFFF" fontName="" fontStyle="1" nesting="0" />
            <WordsStyle name="FOLDER IN COMMENT" fgColor="8E8E8E" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
            <WordsStyle name="DELIMITERS1" fgColor="8E8E8E" bgColor="FFFFFF" fontName="" fontStyle="2" nesting="0" />
            <WordsStyle name="DELIMITERS2" fgColor="8E8E8E" bgColor="FFFFFF" fontName="" fontStyle="2" nesting="0" />
            <WordsStyle name="DELIMITERS3" fgColor="8E8E8E" bgColor="FFFFFF" fontName="" fontStyle="2" nesting="0" />
            <WordsStyle name="DELIMITERS4" fgColor="A82800" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
            <WordsStyle name="DELIMITERS5" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
            <WordsStyle name="DELIMITERS6" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
            <WordsStyle name="DELIMITERS7" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
            <WordsStyle name="DELIMITERS8" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
        </Styles>
    </UserLang>
</NotepadPlus>

Improved Syntax Highlighting

For syntax highlighting that includes some fixes from the above styles, and includes all classes/types found in the native scripts, get it here.

Notable changes:

  • Proper support for multi-line comments
  • Clean color scheme similar to languages like C# and Lua
  • Added all valid types (Var being one of the ones that were missing)
  • Added all native Fallout 4 classes/functions/events (from scripts marked as Native & Hidden)

Basically, this is how the syntax highlighting for Papyrus should be (in a non-IDE environment, anyways). This is strictly for vanilla Fallout 4 and does not include any DLC scripts.

Syntax Highlighting with SKSE 1.7.3 functions

I work on some mods that use SKSE and others that don't so knowing when I'm using an SKSE function is important to me. My User:Cdcooley/Notepad++ Papyrus Syntax Highlighting rules allow me to know which kind of function, event, or script type I'm accessing. The custom color scheme focuses on distinguishing functions with various shades of blue and brown but should be easy enough to change if you prefer something more colorful.

Papyrus Source code Beautifier

  1. Can be found here User:PROXiCiDE/SkyIndent.lua
  2. This script requires LUA to be installed for it to work http://code.google.com/p/luaforwindows/
  3. Installation instructions for binaries only.

    • Download link for Windows binaries (407KB): http://sourceforge.net/projects/luabinaries/files/5.2.1/Executables/ Download the appropriate binaries, depending on whether you are running Windows 32 bits or 64 bits.
    • Extract the binaries (executables). Keep them in their directory. You can rename the directory to something more simple like "lua-5.2.1" or "Lua". "lua-5.2.1" will be used here.
    • Rename "lua52.exe" to "lua.exe". This is for convenience, so you can use the RUN command below as is. Otherwise, you would have to modify the line to read "lua52 "[install path]..."
    • Move the "lua-5.2.1" directory to "C:\Program Files".
    • Optional : Open the "lua-5.2.1" directory and click an empty space in the address bar at the top of the window (next to the "Back" arrow button). The full path to the directory should appear. Copy it, you'll need it for the next steps.

    To add Lua to the environment path (required for the RUN command below to work properly) :

    • Right click on "Computer" (from the left pane of a window, Start menu or elsewhere) and select "Properties".
    • In the left panel, click "Advanced system settings".
    • Click on "Environment Variables" at the bottom.
    • Under "User variables for [your username]" (NOT "System Variables". Do not touch that), there may or may not be a "PATH" variable listed.
      • a) If there isn't one, click on "New...". In "Variable name", type "PATH" without quotes. In "Variable value", enter the path "C:\Program Files\lua-5.2.1" without quotes.
      • b) If there is one, double-click it and at the very end, add ";C:\Program Files\lua-5.2.1" without quotes. You HAVE to include the semicolon (;).
    • Click "OK" on everything.

    You should be set up. To test whether it works, type "cmd" in the search field in the Start menu. A black window should pop up. Type "lua" and hit enter. You should see "Lua 5.2.1 Copyright (C) 1994-2012 Lua-org, PUC-Rio" appear. If you see "'lua' is not recognized as an internal or external command, operable program or batch file.", then you did something wrong. Possible sources of the problem are :

    • You did not rename "lua52.exe" to "lua.exe". Try typing "lua52" in the console window. If it works, then you did not rename the executable properly.
    • You did not type the path properly in the environment variable.
    • You forgot the semicolon (;).

    If everything else fails, you can always use the automated installer found here : http://code.google.com/p/luaforwindows/. Note, however, that the automated installer is larger and will install things that you do not need for this. During the setup, you will be prompted with to select components to install. Uncheck everything except "Lua" (which cannot be unckecked).

  4. To get this to work with Notepad++ just press F5 then type
  5. Copy & Paste the following below in the RUN box
  6. lua "[install path]\skyindent.lua" -b "$(FULL_CURRENT_PATH)"
    
  7. [install path] is the directory where you placed the SkyIndent.lua example "C:\SkyIndent\"
  8. Select Save
  9. Name it: SkyIndent
  10. Select a keyboard shortcut example: CTRL+F6
  11. Usage skyindent.lua [options] [script.psc]
    Available options are:
            -s[number]  Spacing to indent, TAB spacing is default
            -b          Backup the Papyrus Script
    

Papyrus plugin for Notepad++

There is a plugin available that supports extended highlighting for properties and highlighting of custom script names. It also has a interface to view compile output in a list:Papyrus++

Papyrus Function List for Notepad++

In Notepad++, the Function List Panel is a zone to display all the functions (or methods) found in the current file. Users can use the Function List Panel to quickly access a function definition by double clicking the function item on the list. You can customize the Function List to recognize Papyrus by modifying functionList.xml. It can be found in %APPDATA%\Roaming\Notepad++\ or in Notepad++ install directory if you used the zip package. Make a copy for safe keeping, then open it and replace its contents with:

<?xml version="1.0" encoding="UTF-8" ?>
<!--
For learning making your language parser, please check the following link:
http://notepad-plus-plus.org/features/function-list.html
-->
<NotepadPlus>
	<functionList>
		<associationMap>
		<!-- langID:
			L_TEXT: 0     L_PHP: 1        L_C: 2        L_CPP: 3       L_CS: 4         L_OBJC: 5
			L_JAVA: 6     L_RC: 7         L_HTML: 8     L_XML: 9       L_MAKEFILE: 10  L_PASCAL: 11
			L_BATCH:12    L_INI: 13       L_ASCII: 14   L_USER: 15     L_ASP: 16       L_SQL: 17
			L_VB: 18      L_JS: 19        L_CSS: 20     L_PERL: 21     L_PYTHON: 22    L_LUA: 23
			L_TEX: 24     L_FORTRAN: 25   L_BASH: 26    L_FLASH: 27    L_NSIS: 28      L_TCL: 29
			L_LISP: 30    L_SCHEME: 31    L_ASM: 32     L_DIFF: 33     L_PROPS: 34     L_PS: 35
			L_RUBY: 36    L_SMALLTALK:37  L_VHDL: 38    L_KIX: 39      L_AU3: 40       L_CAML: 41
			L_ADA: 42     L_VERILOG: 43   L_MATLAB: 44  L_HASKELL: 45  L_INNO: 46      L_SEARCHRESULT: 47
			L_CMAKE: 48   L_YAML: 49      L_COBOL 50    L_GUI4CLI: 51  L_D: 52         L_POWERSHELL: 53
			L_R: 54       L_JSP: 55
		-->
			<association langID="1" id="php_function"/>
			<association langID="2" id="c_function"/>
			<association langID="3" id="c_cpp_function"/>
			<association langID="6" id="java"/>
			<association langID="9" id="xml_node"/>
			<association langID="12" id="batch_label"/>
			<association langID="13" id="ini_section"/>
			<association langID="19" id="js_function"/>
			<association langID="21" id="perl_function"/>
			<association langID="26" id="bash_function"/>
			<association langID="28" id="nsis_syntax"/>
			<association userDefinedLangName="Papyrus" id="papyrus_function"/>
		<!--
			if langID cannot be found above, you can still set the file extensions
			<association ext=".my_passer_ext1" id="my_passer_id"/>
			<association ext=".my_passer_ext2" id="my_passer_id"/>
			
			for User Defined Languages:
			<association userDefinedLangName="my user defined language" id="my_udl_passer_id"/>
			<association userDefinedLangName="Autocad" id="my_autocad_passer_id"/>
		-->

		</associationMap>
		<parsers>

			<parser id="xml_node" displayName="XML Node" commentExpr="&lt;!--([^-]|-(?!-&gt;))*--&gt;">
				<!-- Only match nodes with at least one attribute -->
				<function
				    mainExpr="&lt;[\w\?]+[\t ]+\w+[\t ]*=[\t ]*&quot;[^&quot;]+&quot;"
					displayMode="$functionName">
					<functionName>
						<nameExpr expr="[^&lt;]*"/>
					</functionName>
				</function>
			</parser>

			<parser id="batch_label" displayName="BAT Label" commentExpr="((::.*?$)|(REM.*?$))">
				<function
				    mainExpr="^[\t ]*:\w+"
					displayMode="$functionName">
					<functionName>
						<nameExpr expr="[^\t :]*"/>
					</functionName>
				</function>
			</parser>

			<parser id="ini_section" displayName="INI Section" commentExpr="((#.*?$)|(;.*?$))">
				<function
				    mainExpr="^[\t ]*[\[&quot;][\w_.; \(\)-]+[\]&quot;]"
					displayMode="$functionName">
					<functionName>
						<nameExpr expr="[^\[\]&quot;]*"/>
					</functionName>
				</function>
			</parser>

			<parser id="java" displayName="Java" commentExpr="((/\*.*?\*)/|(//.**$))">
				<classRange mainExpr="^[\t ]*((public|protected|private|static|final|abstract|synchronized|@(\w)+)\s+)*(class|enum|interface|@interface)\s+\w+(<\s*\w+(,\s*\w+)*\s*>)?(\s+extends\s+\w+)?(\s+implements\s+\w+(,\s*\w+)*)?\s*\{" openSymbole="\{" closeSymbole="\}">
					<className>
						<nameExpr expr="(class|enum|interface|@interface)\s+\w+(<\s*\w+(,\s*\w+)*\s*>)?"></nameExpr>
						<nameExpr expr="\s+\w+(<\s*\w+(,\s*\w+)*\s*>)?"></nameExpr>
						<nameExpr expr="\w+(<\s*\w+(,\s*\w+)*\s*>)?"></nameExpr>
					</className>
					<function mainExpr="^[\t ]*((public|protected|private|static|final|abstract|synchronized|@(\w)+)\s+)*(\w*(\[\s*])*\s+)?(?!(if|while|for|switch|catch|synchronized)\b)\w+(\[\s*])*(<\s*\w+(,\s*\w+)*\s*>)?\s*\([^\)\(]*\)(\s+throws\s+\w+)?\s*\{">
						<functionName>
							<funcNameExpr expr="(?!(if|while|for|switch|catch|synchronized)\b)\w+(\[\s*])*(<\s*\w+(,\s*\w+)*\s*>)?\s*\("></funcNameExpr>
							<funcNameExpr expr="(?!(if|while|for|switch|catch|synchronized)\b)\w+(\[\s*])*(<\s*\w+(,\s*\w+)*\s*>)?"></funcNameExpr>
						</functionName>
					</function>
				</classRange>
			</parser>

			<parser id="c_function" displayName="C source" commentExpr="((/\*.*?\*)/|(//.*?$))">
				<function
				    mainExpr="^[\t ]*((static|const|virtual)[\s]+)?[\w:]+([\s]+[\w]+)?([\s]+|\*[\s]+|[\s]+\*|[\s]+\*[\s]+)([\w_]+[\s]*::)?(?!(if|while|for))[\w_]+[\s]*\([^\)\(]*\)([\s]*const[\s]*)?[\n\s]*\{"
					displayMode="$functionName">
					<functionName>
						<nameExpr expr="(?!(if|while|for))[\w_~]+[\s]*\("/>
						<nameExpr expr="(?!(if|while|for))[\w_~]+"/>
					</functionName>
				</function>
			</parser>
			
			
			<parser id="js_function" displayName="Javascript" commentExpr="((/\*.*?\*)/|(//.*?$))">
				<function
				    mainExpr="((^|[\s]+|[;\}\.])([_A-Za-z][\w_]*\.)*[_A-Za-z][\w_]*[\s]*[=:]|^|[\s;\}]+)[\s]*function([\s]+[_A-Za-z]?[\w_]*\([^\)\(]*\)|\([^\)\(]*\))[\n\s]*\{"
					displayMode="$className->$functionName">
					<functionName>
						<nameExpr expr="[_A-Za-z][\w_]*[\s]*[=:]|[_A-Za-z]?[\w_]*[\s]*\("/>
						<nameExpr expr="[_A-Za-z]?[\w_]*"/>
					</functionName>
					<className>
						<nameExpr expr="([_A-Za-z][\w_]*\.)*[_A-Za-z][\w_]*\."/>
						<nameExpr expr="([_A-Za-z][\w_]*\.)*[_A-Za-z][\w_]*"/>
					</className>
				</function>
			</parser>
			

			<parser id="c_cpp_function" displayName="C++ Class" commentExpr="((/\*.*?\*)/|(//.*?$))">
				<classRange
					mainExpr="^[\t ]*(class|struct)[\t ]+[\w]+[\s]*(:[\s]*(public|protected|private)[\s]+[\w]+[\s]*)?\{"
					openSymbole = "\{"
					closeSymbole = "\}"
					displayMode="node">
					<className>
						<nameExpr expr="(class|struct)[\t ]+[\w]+"/>
						<nameExpr expr="[\t ]+[\w]+"/>
						<nameExpr expr="[\w]+"/>
					</className>
					<function
						mainExpr="^[\t ]*((static|const|virtual)[\s]+)?([\w]+([\s]+[\w]+)?([\s]+|\*[\s]+|[\s]+\*|[\s]+\*[\s]+))?([\w_]+[\s]*::)?(?!(if|while|for|switch))[\w_~]+[\s]*\([^\)\(]*\)([\s]*const[\s]*)?[\n\s]*\{">
						<functionName>
							<funcNameExpr expr="(?!(if|while|for|switch))[\w_~]+[\s]*\("/>
							<funcNameExpr expr="(?!(if|while|for|switch))[\w_~]+"/>
						</functionName>
					</function>
				</classRange>
				<function
				    mainExpr="^[\t ]*((static|const|virtual)[\s]+)?[\w]+([\s]+[\w]+)?([\s]+|\*[\s]+|[\s]+\*|[\s]+\*[\s]+)([\w_]+[\s]*::)?(?!(if|while|for))[\w_]+[\s]*\([^\)\(]*\)([\s]*const[\s]*)?[\n\s]*\{"
					displayMode="$className->$functionName">
					<functionName>
						<nameExpr expr="(?!(if|while|for))[\w_]+[\s]*\("/>
						<nameExpr expr="(?!(if|while|for))[\w_]+"/>
					</functionName>
					<className>
						<nameExpr expr="[\w_]+(?=[\s]*::)"/>
					</className>
				</function>
			</parser>
			
			<parser id="nsis_syntax" displayName="NSIS Syntax" commentExpr="((/\*.*?\*)/|(#.*?$)|(;.*?$))">
				<function
				    mainExpr="^[\t ]*(!macro|Function|Section|SectionGroup)[\t ]+[^\r\n]*$"
					displayMode="$functionName">
					<functionName>
						<nameExpr expr="(?(?=[\t ]*!macro)[\t ]*!macro[\t ]+[^\s]+|[^\r\n]*)"/>
					</functionName>
				</function>
			</parser>
			
			<parser id="perl_function" displayName="Perl">
				<function mainExpr="^[\s]*(?<!#)[\s]*sub[\s]+[\w]+[\s]*\(?[^\)\(]*\)?[\n\s]*\{" displayMode="$className->$functionName">
					<functionName>
						<nameExpr expr="(sub[\s]+)?\K[\w]+"/>
					</functionName>
					<className>
						<nameExpr expr="[\w]+(?=[\s]*::)"/>
					</className>
				</function>
			</parser>
			
            <parser id="php_function" displayName="PHP" commentExpr="((/\*.*?\*)/|(//.*?$))">
                <classRange
                    mainExpr="^[\s]*(class|abstract[\s]+class|final[\s]+class)[\t ]+[\w]+([\s]*|[\s]*(extends|implements)[\s]+[\w\\]+[\s]*)?\{"
                    openSymbole = "\{"
                    closeSymbole = "\}"
                    displayMode="node">
                    <className>
                        <nameExpr expr="(class|abstract[\s]+class|final[\s]+class)[\s]+[\w]+"/>
                        <nameExpr expr="[\s]+[\w]+\Z"/>
                        <nameExpr expr="[\w]+\Z"/>
                    </className>
                    <function
                        mainExpr="^[\s]*((static|public|protected|private|final)*(\s+(static|public|protected|private|final))+[\s]+)?(function[\s]+)+([\w]+([\s]+[\w]+)?([\s]+|\*[\s]+|[\s]+\*|[\s]+\*[\s]+))?([\w_]+[\s]*::)?(?!(if|while|for|switch))[\w_~]+[\s]*\([^\{]*\{">
                        <functionName>
                            <funcNameExpr expr="(?!(if|while|for|switch))[\w_]+[\s]*\([^\{]*"/>
                            <!-- comment below node if want display method with parmas -->
                            <funcNameExpr expr="(?!(if|while|for|switch))[\w_]+"/>
                        </functionName>
                    </function>
                </classRange>
                <function
                    mainExpr="^[\s]*function[\s]+\w+\("

                    displayMode="$className->$functionName">
                    <functionName>
                        <nameExpr expr="(?!(if|while|for))[\w_]+[\s]*\("/>
                        <nameExpr expr="(?!(if|while|for))[\w_]+"/>
                    </functionName>
                    <className>
                        <nameExpr expr="[\w_]+(?=[\s]*::)"/>
                    </className>
                </function>
            </parser>
			<parser id="bash_function" displayName="Shell" commentExpr="(#.*?$)">
				<function
					mainExpr="^[\t ]*(function[\t\r\n ]*)?([a-zA-Z0-9_])+[\t\r\n ]*(\([^\)]*\))?[\t\r\n ]*(\{)[^(\})\r\n\t ]*"
					displayMode="$functionName">
					<functionName>
						<nameExpr expr="[^{]*"/>
					</functionName>
				</function>
			</parser>
			<parser id="papyrus_function" displayName="Papyrus" commentExpr="(;.*?$)">
                <function displayMode="$functionName"
                    mainExpr="^[\t ]*([\w\[\]]+[\t ]+)?(function|event)[\t ]+\w+[\t ]*\(.*?\)">
                    <functionName>
                        <nameExpr expr="\w+[\t ]*\(.*?\)"/>
                    </functionName>
                </function>
            </parser>
			
		</parsers>
	</functionList>
</NotepadPlus>

This code assumes your Papyrus custom-defined language is named "Papyrus" in Notepad++. If you chose a different name, replace the line

<association userDefinedLangName="Papyrus" id="papyrus_function"/>

with

<association userDefinedLangName="YOUR_LANGUAGE_NAME" id="papyrus_function"/>

where YOUR_LANGUAGE_NAME is the name of your custom-defined language.


Language: English  • français