Skip to content

Commit

Permalink
feat: new alertREPL function
Browse files Browse the repository at this point in the history
Using a new feature in Julia 1.5 this allows the user to
send an alert anytime something runs for too long in the REPL.
  • Loading branch information
haberdashPI committed Aug 20, 2020
1 parent b236cdd commit 2e05bd6
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 20 deletions.
4 changes: 3 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
name = "Alert"
uuid = "28312eec-4d86-447d-83ad-bc2b262de792"
authors = ["David Little <[email protected]> and contributors"]
version = "0.1.2"
version = "0.1.3"

[deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

[compat]
julia = "1"
51 changes: 39 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
# Alert

Alert provides a cross-platform means of displaying a notification to the user
in Julia. It should work on MacOS, Windows 10 (even under WSL2) or Linux. This is handy for
long-running scripts; just add `alert()` to the end of the script, and go work
on something else until you see the notification. To use it just run `alert`,
like so.
Alert provides a cross-platform means of displaying a notification to the user in Julia. It
should work on MacOS, Windows 10 (even under WSL2) and many flavors of Linux. This is handy
for long-running scripts.

There are three ways to use alert:

1. Call `alert()` after a long-running piece of code.
2. Put long-running code inside the `@alert` macro.
3. Call `alertREPL` and any long-running code sent to the REPL will display a notification.

Before using `alert()` at the end of a long-running script, it would be good to
test that it actually works on your system: some linux distros may not have
an appropriate program installed to display the notification. If it doesn't
work, just read the error message that is displayed to see what program you need
to install.

## The `alert()` function

To use `alert()` just add it to some long-running code.

```julia

Expand All @@ -17,19 +31,32 @@ end
alert("Your julia script is finished!")
```

Before using `alert()` at the end of a long-running script, it would be good to
test that it actually works on your system: e.g. some linux distros may not have
an appropriate program installed to display the notification. If it doesn't
work, just read the error message that is displayed to see what program you need
to install.
## The `@alert` macro

The package also provides `@alert`, which can be used to notify you when a block
of code has finished. It only displays a message if the code runs for longer
The `@alert` macro displays a message if the code passed to it runs for longer
than 2 seconds (or a custom value). This is especially handy when using
[`ProgressMeter`](https://github.com/timholy/ProgressMeter.jl), like so.

```julia
@alert @showprogress for i in 1:10_000
long_running_function()
end
```

## The REPL hook

In Julia 1.5 or greater, if you want any long-running command at the REPL to send a
notification, you can use `alertREPL`. It takes the same arguments as `@alert` and will wrap
any code passed to the Julia REPL in a call to `@alert`.

You can add the following to your `startup.jl` file to have it work in every Julia
session.

```julia
try
using Alert
alertREPL()
catch e
@warn e.msg
end
```
54 changes: 47 additions & 7 deletions src/Alert.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,46 @@
module Alert
using Base64
using Dates
using Printf
using REPL

export alert, @alert
export alertREPL, alert, @alert

function __init__()
if VERSION >= v"1.5"
pushfirst!(REPL.repl_ast_transforms, with_repl_alert)
end
end

const repl_alert_options = Ref((Inf,"Done!"))
function with_repl_alert(ex)
if !isinf(repl_alert_options[][1])
Expr(:toplevel, quote
@alert $(repl_alert_options[][1]) $(repl_alert_options[][2]) $ex
end)
else
ex
end
end

"""
alertREPL([duration=2.0], [message="Done!"])
Wraps all code passed to the REPL in an `@alert` macro with the given arguments. Hence,
if anything you run in the REPL takes longer than `duration` seconds, an alert notification
will be displayed. You can set the duration to `Inf` to turn off the notification.
"""
function alertREPL(args...)
repl_alert_options[] = __at_alert_options__(args...)
dur = repl_alert_options[][1]
if !isinf(dur)
secs = @sprintf("%1.2f s", repl_alert_options[][1])
@info "Alert will be sent if REPL line takes longer than $secs to complete. See "*
"documentation for `Alert.alertREPL`"
else
@info "REPL alerts have been turned off."
end
end

"""
@alert [duration] [message] begin
Expand All @@ -17,23 +55,25 @@ macro alert(args...)
error("Missing body for @alert macro.")
end
options = args[1:end-1]
body = args[end]
body = args[end]

return quote
start_time = Dates.now()
$(esc(body))
result = $(esc(body))
delay, msg = Alert.__at_alert_options__($options...)
if (Dates.now() - start_time) > Dates.Millisecond(round(Int,1000delay))
if !isinf(delay) && (Dates.now() - start_time) > Dates.Millisecond(round(Int,1000delay))
alert(msg)
end

result
end
end

__at_alert_options__() = 2.0, "Done!"
__at_alert_options__(str::AbstractString) = 2.0, str
__at_alert_options__(num::Number) = num, "Done!"
__at_alert_options__(str::AbstractString,num::Number) = num, str
__at_alert_options__(num::Number,str::AbstractString) = num, str
__at_alert_options__(num::Number) = convert(Float64,num), "Done!"
__at_alert_options__(str::AbstractString,num::Number) = convert(Float64,num), str
__at_alert_options__(num::Number,str::AbstractString) = convert(Float64,num), str

# determine if the current system is Linux under WSL
function iswsl()
Expand Down

2 comments on commit 2e05bd6

@haberdashPI
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator register()

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/19863

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.1.3 -m "<description of version>" 2e05bd6da3ba98b85f4cd7fce2aaf545f2f8392f
git push origin v0.1.3

Please sign in to comment.