Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 29 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,28 +55,24 @@ chmod +x runner.sh
### Linux and macOS

```bash
# Run a specific file
./runner.sh HelloWorld.java

# If there is only one .java file in the current directory, the argument is optional
./runner.sh

# If no .java file is found in the current directory, runner looks inside examples/ automatically
./runner.sh

# Enable watch mode: recompiles and reruns every time the file is saved
./runner.sh HelloWorld.java --watch

# Show help
./runner.sh HelloWorld.java # run a specific file
./runner.sh # auto-detect
./runner.sh HelloWorld.java --watch # watch mode
./runner.sh *.java --all # compile all .java in the directory together
./runner.sh Main.java --input in.txt # pipe file into stdin
./runner.sh Main.java --output out.txt
./runner.sh Main.java --classpath lib/junit.jar
./runner.sh --help
```

### Windows (Command Prompt)

```cmd
runner.bat HelloWorld.java
runner.bat
runner.bat HelloWorld.java --watch
runner.bat Main.java --all
runner.bat Main.java --input in.txt --output out.txt
runner.bat Main.java --classpath lib\junit.jar
```

### Windows (PowerShell)
Expand All @@ -85,12 +81,26 @@ runner.bat HelloWorld.java --watch

```powershell
.\runner.ps1 HelloWorld.java
.\runner.ps1
.\runner.ps1 HelloWorld.java -Watch
.\runner.ps1 Main.java -All
.\runner.ps1 Main.java -InputFile in.txt -OutputFile out.txt
.\runner.ps1 Main.java -Classpath lib\junit.jar
```

---

## Flags

| Flag | Short form (PS1) | Description |
|------|-----------------|-------------|
| `--watch` | `-Watch` | Recompile and rerun every time the file is saved |
| `--all` | `-All` | Compile all `.java` files in the same directory together |
| `--input <file>` | `-InputFile <file>` | Pipe a file into stdin when running |
| `--classpath <path>` | `-Classpath <path>` | Append to the compile and run classpath |
| `--output <file>` | `-OutputFile <file>` | Save program output to a file (also prints to terminal) |

---

## File detection order

When no file is passed as an argument, runner searches in this order:
Expand Down Expand Up @@ -248,10 +258,10 @@ The `examples/` folder contains three files you can use to verify the setup or a

### Phase 4 - Features

- [ ] Multi-file support: compile all `.java` files in the current directory together
- [ ] `--input file.txt` flag to pipe a file into stdin
- [ ] `--classpath path` flag to append jars to the compile and run commands
- [ ] `--output file.txt` flag to save program output to a file
- [x] `--all` flag: compile all `.java` files in the same directory together
- [x] `--input <file>` flag to pipe a file into stdin
- [x] `--classpath <path>` flag to append jars to the compile and run commands
- [x] `--output <file>` flag to save program output to a file (also prints to terminal)

### Phase 5 - Community

Expand Down
90 changes: 72 additions & 18 deletions runner.bat
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@echo off
REM ─────────────────────────────────────────────────────────────
REM java-runner - run Java exercises without an IDE (Windows)
REM Usage: runner.bat [File.java] [--watch]
REM Usage: runner.bat [File.java] [--watch] [--all] [--input f] [--classpath p] [--output f]
REM ─────────────────────────────────────────────────────────────

setlocal EnableDelayedExpansion
Expand All @@ -17,14 +17,25 @@ set "RESET=[0m"

set "FILE="
set "WATCH=false"
set "ALL=false"
set "INPUT_FILE="
set "EXTRA_CP="
set "OUTPUT_FILE="

REM ── Parse arguments ───────────────────────────────────────────
for %%A in (%*) do (
if "%%A"=="--watch" set "WATCH=true"
if "%%~xA"==".java" set "FILE=%%A"
if "%%A"=="--help" goto :help
if "%%A"=="-h" goto :help
)
:parse_args
if "%~1"=="" goto :end_parse
if /i "%~1"=="--watch" ( set "WATCH=true" & shift & goto :parse_args )
if /i "%~1"=="--all" ( set "ALL=true" & shift & goto :parse_args )
if /i "%~1"=="--input" ( shift & set "INPUT_FILE=%~1" & shift & goto :parse_args )
if /i "%~1"=="--classpath" ( shift & set "EXTRA_CP=%~1" & shift & goto :parse_args )
if /i "%~1"=="--output" ( shift & set "OUTPUT_FILE=%~1" & shift & goto :parse_args )
if /i "%~1"=="--help" goto :help
if /i "%~1"=="-h" goto :help
if "%~x1"==".java" ( set "FILE=%~1" & shift & goto :parse_args )
shift
goto :parse_args
:end_parse

REM ── Auto-detect .java file ────────────────────────────────────
if "%FILE%"=="" (
Expand Down Expand Up @@ -86,36 +97,78 @@ exit /b

REM ── Help ──────────────────────────────────────────────────────
:help
echo Usage: runner.bat [File.java] [--watch]
echo File.java Java file to compile and run
echo --watch Recompile and rerun on every file change
echo Usage: runner.bat [File.java] [options]
echo.
echo Options:
echo --watch Recompile and rerun on every file change
echo --all Compile all .java files in the same directory together
echo --input ^<file^> Pipe file contents into stdin when running
echo --classpath ^<path^> Append to the compile and run classpath
echo --output ^<file^> Save program output to file (also prints to terminal)
exit /b

REM ── Main run function ─────────────────────────────────────────
:run
for %%F in ("%FILE%") do set "CLASSNAME=%%~nF"
for %%F in ("%FILE%") do set "FILEDIR=%%~dpF"
set "TMPDIR=%TEMP%\java-runner-%RANDOM%"
mkdir "%TMPDIR%" 2>nul

REM Build classpath
if defined EXTRA_CP (
set "CP=!TMPDIR!;!EXTRA_CP!"
set "CP_FLAG=-cp "!EXTRA_CP!""
) else (
set "CP=!TMPDIR!"
set "CP_FLAG="
)

echo.
echo !CYAN![....] Compiling %CLASSNAME%.java...!RESET!
echo !CYAN![....] Compiling !CLASSNAME!.java...!RESET!

REM Choose sources: --all compiles every .java in the same directory
if "!ALL!"=="true" (
set "JAVA_FILES="
for %%F in ("!FILEDIR!*.java") do set "JAVA_FILES=!JAVA_FILES! "%%~fF""
javac !CP_FLAG! -d "!TMPDIR!" !JAVA_FILES! 2>"!TMPDIR!\errors.txt"
) else (
javac !CP_FLAG! -d "!TMPDIR!" "%FILE%" 2>"!TMPDIR!\errors.txt"
)

javac -d "%TMPDIR%" "%FILE%" 2>"%TMPDIR%\errors.txt"
if errorlevel 1 (
echo !RED![FAIL] Compilation failed:!RESET!
echo.
type "%TMPDIR%\errors.txt"
rmdir /s /q "%TMPDIR%"
type "!TMPDIR!\errors.txt"
rmdir /s /q "!TMPDIR!"
exit /b 1
)

echo !GREEN![ OK ] Compiled successfully!RESET!
echo !CYAN!───────────────────────── output ─────────────────────────!RESET!

set "START_TIME=%TIME%"
java -cp "%TMPDIR%" "%CLASSNAME%"
set "JAVA_EXIT=%ERRORLEVEL%"
set "END_TIME=%TIME%"

REM Run java with optional input and output redirection
if defined OUTPUT_FILE (
set "TMPOUT=!TMPDIR!\output.txt"
if defined INPUT_FILE (
java -cp "!CP!" "!CLASSNAME!" < "!INPUT_FILE!" > "!TMPOUT!"
) else (
java -cp "!CP!" "!CLASSNAME!" > "!TMPOUT!"
)
set "JAVA_EXIT=!ERRORLEVEL!"
set "END_TIME=!TIME!"
type "!TMPOUT!"
copy "!TMPOUT!" "!OUTPUT_FILE!" >nul
) else (
if defined INPUT_FILE (
java -cp "!CP!" "!CLASSNAME!" < "!INPUT_FILE!"
) else (
java -cp "!CP!" "!CLASSNAME!"
)
set "JAVA_EXIT=!ERRORLEVEL!"
set "END_TIME=!TIME!"
)

REM Parse start time (HH:MM:SS.cc)
for /f "tokens=1-4 delims=:,. " %%a in ("!START_TIME!") do (
Expand All @@ -133,8 +186,9 @@ REM ── Main run function ─────────────────
echo !RED![FAIL] Finished in !ELAPSED_MS!ms ^(exit code !JAVA_EXIT!^)!RESET!
) else (
echo !GREEN![ OK ] Finished in !ELAPSED_MS!ms!RESET!
if defined OUTPUT_FILE echo !CYAN! Output saved to: !OUTPUT_FILE!!RESET!
)
echo.

rmdir /s /q "%TMPDIR%"
rmdir /s /q "!TMPDIR!"
exit /b !JAVA_EXIT!
55 changes: 46 additions & 9 deletions runner.ps1
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
# java-runner - run Java exercises without an IDE (PowerShell)
# Usage: .\runner.ps1 [File.java] [-Watch]
# Usage: .\runner.ps1 [File.java] [-Watch] [-All] [-InputFile f] [-Classpath p] [-OutputFile f]

param(
[string]$JavaFile = "",
[switch]$Watch,
[switch]$All,
[string]$InputFile = "",
[string]$Classpath = "",
[string]$OutputFile = "",
[switch]$Help
)

if ($Help) {
Write-Host "Usage: .\runner.ps1 [File.java] [-Watch]"
Write-Host " File.java Java file to compile and run (optional if only one .java exists)"
Write-Host " -Watch Recompile and rerun on every file save (event-based)"
Write-Host "Usage: .\runner.ps1 [File.java] [options]"
Write-Host ""
Write-Host "Options:"
Write-Host " -Watch Recompile and rerun on every file save (event-based)"
Write-Host " -All Compile all .java files in the same directory together"
Write-Host " -InputFile <file> Pipe file contents into stdin when running"
Write-Host " -Classpath <path> Append to the compile and run classpath"
Write-Host " -OutputFile <file> Save program output to file (also prints to terminal)"
exit 0
}

Expand Down Expand Up @@ -46,14 +55,27 @@ $JavaFile = (Resolve-Path $JavaFile).Path

function Invoke-Run {
$className = [System.IO.Path]::GetFileNameWithoutExtension($JavaFile)
$tmpDir = Join-Path $env:TEMP ("java-runner-" + [System.IO.Path]::GetRandomFileName())
$fileDir = [System.IO.Path]::GetDirectoryName($JavaFile)
$tmpDir = Join-Path $env:TEMP ("java-runner-" + [System.IO.Path]::GetRandomFileName())
New-Item -ItemType Directory -Path $tmpDir -Force | Out-Null

# Build classpath
$cp = $tmpDir
if ($Classpath) { $cp = "$tmpDir;$Classpath" }

Write-Host ""
Write-Host "[....] Compiling $className.java..." -ForegroundColor Cyan

# Choose sources: -All compiles every .java in the same directory
$errFile = Join-Path $tmpDir "errors.txt"
& javac -d $tmpDir $JavaFile 2>$errFile
if ($All) {
$sources = (Get-ChildItem -Path $fileDir -Filter "*.java" -File | ForEach-Object { $_.FullName })
$cpArgs = if ($Classpath) { @("-cp", $Classpath) } else { @() }
& javac @cpArgs -d $tmpDir @sources 2>$errFile
} else {
$cpArgs = if ($Classpath) { @("-cp", $Classpath) } else { @() }
& javac @cpArgs -d $tmpDir $JavaFile 2>$errFile
}
$compileExit = $LASTEXITCODE

if ($compileExit -ne 0) {
Expand All @@ -68,8 +90,22 @@ function Invoke-Run {
Write-Host "───────────────────────── output ─────────────────────────" -ForegroundColor Cyan

$sw = [System.Diagnostics.Stopwatch]::StartNew()
& java -cp $tmpDir $className
$javaExit = $LASTEXITCODE

# Run with optional input/output redirection
if ($InputFile -and $OutputFile) {
& java -cp $cp $className < $InputFile | Tee-Object -FilePath $OutputFile
$javaExit = $LASTEXITCODE
} elseif ($InputFile) {
& java -cp $cp $className < $InputFile
$javaExit = $LASTEXITCODE
} elseif ($OutputFile) {
& java -cp $cp $className | Tee-Object -FilePath $OutputFile
$javaExit = $LASTEXITCODE
} else {
& java -cp $cp $className
$javaExit = $LASTEXITCODE
}

$sw.Stop()
$elapsed = $sw.ElapsedMilliseconds

Expand All @@ -78,6 +114,7 @@ function Invoke-Run {
Write-Host "[FAIL] Finished in ${elapsed}ms (exit code $javaExit)" -ForegroundColor Red
} else {
Write-Host "[ OK ] Finished in ${elapsed}ms" -ForegroundColor Green
if ($OutputFile) { Write-Host " Output saved to: $OutputFile" -ForegroundColor Cyan }
}
Write-Host ""

Expand All @@ -88,7 +125,7 @@ function Invoke-Run {
if ($Watch) {
Write-Host "[WATCH] Watch mode enabled - save the file to rerun" -ForegroundColor Yellow

$dir = Split-Path $JavaFile -Parent
$dir = Split-Path $JavaFile -Parent
$filename = Split-Path $JavaFile -Leaf

Clear-Host
Expand Down
Loading
Loading