StupidlySimpleNotes.psm1
<#
.SYNOPSIS A stupidly simple note-taking tool .DESCRIPTION StupidlySimpleNotes (SSN) is a simple note-taking tool, that allows you to easily create, display and search notes, right from your PowerShell terminal. #> $SsnDirectory = (Resolve-Path '~/ssn').Path <# .SYNOPSIS Create a new note .DESCRIPTION Create a new note at the given path. The body of the note can be supplied as arguments, or if omitted, the draft note will open in Visual Studio Code by default. Input from the pipeline will be appended to the bottom of the note, allowing you to easily capture the output of another command in a note. .PARAMETER Path The path for the note. If not supplied, the path will be automatically generated based on the current timestamp .PARAMETER InputObject Allows lines of text to be appended to the note from the pipeline .PARAMETER Edit Whether to edit the note in Visual Studio Code before saving .PARAMETER Note The body of the note #> Function New-Note { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification='Creating a note is non-destructive')] [CmdletBinding()] Param( [Parameter()] [ArgumentCompleter({ Get-PathCompleter @args })] [string] $Path, [Parameter(ValueFromPipeline)] [string] $InputObject, [Parameter()] [switch] $Edit, [Parameter(Position=0, ValueFromRemainingArguments)] [string] $Note ) Begin { $lines = @() If (-not [string]::IsNullOrWhiteSpace($Note)) { $lines += $Note,'' } } Process { $lines += $InputObject } End { If ([string]::IsNullOrWhiteSpace($Path)) { $ticks = ([DateTime]::MaxValue - [DateTime]::Now).Ticks $Path = "$ticks.txt" } If (-not $Path.EndsWith('.txt')) { $Path = "$Path.txt" } $fullPath = Join-Path $SsnDirectory $Path $directory = [System.IO.Path]::GetDirectoryName($fullPath) If (-not (Test-Path $directory)) { [void](New-Item -ItemType Directory -Path $directory) } If ($Edit -or ($lines.Count -eq 1)) { $tmp = New-TemporaryFile $lines | Out-File -FilePath $tmp code -w $tmp Get-Content -Path $tmp | Out-File -FilePath $fullPath } Else { $lines | Out-File -FilePath $fullPath } } } <# .SYNOPSIS Show the contents of a note .DESCRIPTION Show the contents of a note .PARAMETER Path The path to the note to show #> Function Get-Note { [CmdletBinding()] Param( [Parameter(Mandatory)] [ArgumentCompleter({ Get-PathCompleter @args })] [string] $Path ) If (-not $Path.EndsWith('.txt')) { $Path = "$Path.txt" } Get-Content -Path (Join-Path $SsnDirectory $Path) } <# .SYNOPSIS Show the contents of several notes .DESCRIPTION Show the contents of all notes under a given path and/or within a given timeframe .PARAMETER Today Show notes created today .PARAMETER This Show notes created this week/month/year .PARAMETER From Show notes created after this time .PARAMETER To Show notes created before this time. If omitted, will show notes up to present .PARAMETER Path The path to search under #> Function Get-Notes { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification='It gets multiple notes')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidAssignmentToAutomaticVariable', '', Justification='Call needs to be -This')] [CmdletBinding(DefaultParameterSetName='FromTo')] Param( [Parameter(ParameterSetName='Today')] [switch] $Today, [Parameter(Position=0, ParameterSetName='This')] [string] [ValidateSet('week', 'month', 'year')] $This, [Parameter(ParameterSetName='FromTo')] [DateTime] $From, [Parameter(ParameterSetName='FromTo')] [DateTime] $To, [Parameter()] [ArgumentCompleter({ Get-PathCompleter @args })] [string] $Path ) Switch ($PSCmdlet.ParameterSetName) { 'Today' { If (-not $Today) { Write-Error "Not today!" Return } $From = [DateTime]::Today $To = [DateTime]::MaxValue } 'This' { Switch ($This) { 'week' { $date = [DateTime]::Today; $From = $date.AddDays(1-$date.DayOfWeek) } 'month' { $date = [DateTime]::Today; $From = $date.AddDays(1-$date.Day) } 'year' { $date = [DateTime]::Today; $From = $date.AddDays(1-$date.DayOfYear) } } $To = [DateTime]::MaxValue } 'FromTo' { If ($null -eq $To) { $To = [DateTime]::MaxValue } } } If ([string]::IsNullOrWhiteSpace($Path) -and $null -eq $From) { Write-Error "Must supply either path or time range" Return } If ($null -eq $From) { $From = [DateTime]::MinValue } $Path = Join-Path $SsnDirectory $Path Get-ChildItem ` -Path $Path ` -File ` -Recurse ` | Where-Object { $From -le $_.LastWriteTime -and $_.LastWriteTime -lt $To } ` | ForEach-Object { $file = $_ Write-Output (Get-NoteName $file) Write-Output '' Get-Content -Path $file.FullName Write-Output '' Write-Output '' } } <# .SYNOPSIS Search for notes .DESCRIPTION Search for notes (optionally under a given path) which match the given search pattern (regex) .PARAMETER Path The path to search under .PARAMETER Search The pattern to search for in the body of notes (regex) #> Function Find-Notes { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification='It gets multiple notes')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'Search', Justification='False positive')] [CmdletBinding()] Param( [Parameter()] [ArgumentCompleter({ Get-PathCompleter @args })] [string] $Path, [Parameter(Position=0, Mandatory, ValueFromRemainingArguments)] [string] $Search ) $Path = Join-Path $SsnDirectory $Path Get-ChildItem ` -Path $Path ` -File ` -Recurse ` | Where-Object { Get-Content -Path $_.FullName ` | Where-Object { $_ -match $search } } ` | ForEach-Object { $file = $_ Write-Output (Get-NoteName $file) Write-Output '' Get-Content -Path $file.FullName Write-Output '' Write-Output '' } } <# .SYNOPSIS Edit the contents of a note .DESCRIPTION Edit the contents of a note .PARAMETER Path The path to the note to edit #> Function Edit-Note { [CmdletBinding()] Param( [Parameter(Mandatory)] [ArgumentCompleter({ Get-PathCompleter @args })] [string] $Path ) If (-not $Path.EndsWith('.txt')) { $Path = "$Path.txt" } code -w (Join-Path $SsnDirectory $Path) } <# .SYNOPSIS Move or rename a note .DESCRIPTION Move or rename a note .PARAMETER Path The path to the note to move or rename .PARAMETER Destination The new path for the note . #> Function Move-Note { [CmdletBinding(SupportsShouldProcess)] Param( [Parameter(Mandatory)] [ArgumentCompleter({ Get-PathCompleter @args })] [string] $Path, [Parameter(Mandatory)] [ArgumentCompleter({ Get-PathCompleter @args })] [string] $Destination ) If (-not $Path.EndsWith('.txt')) { $Path = "$Path.txt" } If (-not $Destination.EndsWith('.txt')) { $Destination = "$Destination.txt" } If ($PSCmdlet.ShouldProcess( "Performing the operation `"Move Note`" on target `"Item: $Path Destination: $Destination`"", "Are you sure you want to perform this action?`nPerforming the operation `"Move Note`" on target `"Item: $Path Destination: $Destination`"", "Confirm" )) { Move-Item ` -Path (Join-Path $SsnDirectory $Path) ` -Destination (Join-Path $SsnDirectory $Destination) } } Function Get-PathCompleter { $Path = $args[2] $fullPath = Join-Path $SsnDirectory $Path Get-ChildItem -Path $fullPath | ForEach-Object { Get-NoteName $_ } } Function Get-NoteName { Param( $FilePath ) $FilePath.FullName.Substring($SsnDirectory.Length) } |