Skip to content

Commit b0730e5

Browse files
Merge pull request #5 from php-debugger/installation-page
add installation page
2 parents 7f915f7 + e175c95 commit b0730e5

11 files changed

Lines changed: 393 additions & 37 deletions

File tree

docs/getting-started/docker.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
title: Docker
3+
---
4+
5+
Run PHP Debugger in a container using an image with the debugger already compiled
6+
into the interpreter, with nothing to install.
7+
8+
:::note
9+
This page is a work in progress — full documentation is coming soon.
10+
:::
11+
12+
In the meantime, the [installer](./installation.mdx) covers installing directly
13+
onto your machine.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
title: More install options
3+
---
4+
5+
Ways to install PHP Debugger beyond the installer — prebuilt binaries, package
6+
managers, and building from source.
7+
8+
:::note
9+
This page is a work in progress — full documentation is coming soon.
10+
:::
11+
12+
For the recommended route, see [Installation](./installation.mdx).

docs/getting-started/installation.md

Lines changed: 0 additions & 34 deletions
This file was deleted.
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
---
2+
title: Installation
3+
---
4+
5+
import InstallCommand from '@site/src/components/InstallCommand';
6+
7+
The quickest way to get PHP Debugger onto your machine is the installer, a small
8+
command-line tool that fetches the right build for your system and puts it in
9+
place. Installing it is a single command.
10+
11+
## 1. Get the installer
12+
13+
<InstallCommand />
14+
15+
The script downloads the latest release and drops the `php-debugger` binary into
16+
the current directory. Set `INSTALL_DIR` if you would rather it landed somewhere
17+
else.
18+
19+
:::tip[Prefer Docker?]
20+
21+
Use a container image instead — see [Docker](./docker.md).
22+
23+
:::
24+
25+
## 2. Install the debugger
26+
27+
The installer offers two ways to get a working debugger. Run it with no arguments
28+
for the default:
29+
30+
```bash
31+
php-debugger install
32+
```
33+
34+
That installs a **self-contained PHP interpreter** with the debugger compiled
35+
straight into it, and makes it the active `php` on your PATH. Nothing else on your
36+
system needs to change.
37+
38+
If you would rather keep the PHP you already have, install **only the extension**
39+
into it:
40+
41+
```bash
42+
php-debugger install --extension-only
43+
```
44+
45+
The two are mutually exclusive, and the installer knows it: installing the
46+
interpreter removes any extension you had installed, so you never end up running
47+
both at once.
48+
49+
A few flags are worth knowing:
50+
51+
| Flag | What it does |
52+
| --- | --- |
53+
| `-u, --user` | Install into a per-user directory, so no `sudo` is needed. The default is system-wide. |
54+
| `-p, --php <x.y>` | Pick the PHP version to install. Defaults to the latest, and applies to the interpreter only. |
55+
| `-e, --extension-only` | Install just the extension into your current PHP. |
56+
| `-z, --zts` | Install a thread-safe build instead of the default non-thread-safe one. |
57+
| `-y, --yes` | Answer yes to every prompt, for unattended or CI use. |
58+
59+
If the directory it installs into is not on your `PATH`, the installer prints the
60+
exact line you need to add.
61+
62+
## Changing your mind
63+
64+
Nothing here is a one-way door. Whether you installed the interpreter or just the
65+
extension, whatever it replaced is backed up first — the PHP you already had, or
66+
the ini configuration it changed. To put things back as they were:
67+
68+
```bash
69+
php-debugger uninstall
70+
```
71+
72+
That removes whatever was installed and restores your previous setup from the
73+
backup — the interpreter it replaced, or the ini configuration it changed. You do
74+
not have to tell it which kind you installed; it works that out for itself.
75+
76+
The installer also tries hard not to leave you with a broken `php` in the first
77+
place. It runs the downloaded interpreter before changing anything, so a build
78+
that cannot run on your system is never installed. After activating it, it checks
79+
that `php` still runs and reports the debugger module, and rolls everything back to
80+
the previous working state if either check fails.
81+
82+
## Staying up to date
83+
84+
To move to the latest release:
85+
86+
```bash
87+
php-debugger update
88+
```
89+
90+
It takes no arguments. Whether you installed the interpreter or just the
91+
extension, it detects what is there and reinstalls the same thing against the
92+
latest version.
93+
94+
:::info[Prefer to install some other way?]
95+
96+
See [More install options](./install-options.md).
97+
98+
:::
99+
100+
## Next steps
101+
102+
With the debugger installed, point your editor at it and set your first
103+
breakpoint:
104+
105+
- [Quick Start](./quick-start.md)
106+
- [Configuration](./configuration.md)

docs/getting-started/introduction.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ because when you are not using it you can barely tell it is there.
1515

1616
Ready to get started? Install PHP Debugger and try the quick start guide:
1717

18-
- [Installation Guide](./installation.md)
18+
- [Installation Guide](./installation.mdx)
1919
- [Quick Start](./quick-start.md)

docs/getting-started/quick-start.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Quick Start
33
---
44

5-
Get up and running with PHP Debugger in a few minutes. This guide assumes you have already [installed](./installation.md) the extension.
5+
Get up and running with PHP Debugger in a few minutes. This guide assumes you have already [installed](./installation.mdx) the extension.
66

77
## 1. Enable the debugger
88

docusaurus.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ const config = {
125125
prism: {
126126
theme: prismThemes.github,
127127
darkTheme: prismThemes.dracula,
128-
additionalLanguages: ['php', 'ini', 'bash'],
128+
additionalLanguages: ['php', 'ini', 'bash', 'powershell'],
129129
},
130130
}),
131131
};

sidebars.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ const sidebars = {
1212
items: [
1313
'getting-started/introduction',
1414
'getting-started/installation',
15+
'getting-started/docker',
16+
'getting-started/install-options',
1517
'getting-started/quick-start',
1618
'getting-started/configuration',
1719
],
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import {useEffect, useRef, useState} from 'react';
2+
import clsx from 'clsx';
3+
import CodeBlock from '@theme/CodeBlock';
4+
import styles from './styles.module.css';
5+
6+
/* macOS and Linux run the same script -- it detects the OS and architecture
7+
itself -- so both tabs deliberately show the same command. */
8+
const UNIX_COMMAND =
9+
'curl -fsSL https://github.com/php-debugger/installer/releases/latest/download/install.sh | sh';
10+
const WINDOWS_COMMAND =
11+
'powershell -c "irm https://github.com/php-debugger/installer/releases/latest/download/install.ps1 | iex"';
12+
13+
const iconProps = {
14+
width: 15,
15+
height: 15,
16+
viewBox: '0 0 24 24',
17+
fill: 'none',
18+
stroke: 'currentColor',
19+
strokeWidth: 2,
20+
strokeLinecap: 'round',
21+
strokeLinejoin: 'round',
22+
'aria-hidden': true,
23+
};
24+
25+
const CopyIcon = () => (
26+
<svg {...iconProps}>
27+
<rect x="9" y="9" width="11" height="11" rx="2" />
28+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
29+
</svg>
30+
);
31+
32+
const CheckIcon = () => (
33+
<svg {...iconProps}>
34+
<path d="M20 6 9 17l-5-5" />
35+
</svg>
36+
);
37+
38+
const PLATFORMS = [
39+
{id: 'macos', label: 'macOS', language: 'bash', command: UNIX_COMMAND},
40+
{id: 'linux', label: 'Linux', language: 'bash', command: UNIX_COMMAND},
41+
{id: 'windows', label: 'Windows', language: 'powershell', command: WINDOWS_COMMAND},
42+
];
43+
44+
function detectPlatform() {
45+
const ua = navigator.userAgent;
46+
if (/Windows/i.test(ua)) {
47+
return 'windows';
48+
}
49+
if (/Mac OS X|Macintosh/i.test(ua)) {
50+
return 'macos';
51+
}
52+
/* Android reports Linux too, and the command is the same either way. */
53+
if (/Linux|Android|X11/i.test(ua)) {
54+
return 'linux';
55+
}
56+
return null;
57+
}
58+
59+
export default function InstallCommand() {
60+
/* The page is prerendered without knowing the visitor's OS, so start on macOS
61+
and correct it after mounting. Detecting in an effect rather than during
62+
render keeps the first client render identical to the server's, which is
63+
what hydration compares. A visitor who picks a tab keeps their choice --
64+
the effect only runs on mount. */
65+
const [platform, setPlatform] = useState('macos');
66+
67+
useEffect(() => {
68+
const detected = detectPlatform();
69+
if (detected) {
70+
setPlatform(detected);
71+
}
72+
}, []);
73+
74+
const active = PLATFORMS.find((p) => p.id === platform) ?? PLATFORMS[0];
75+
const [copied, setCopied] = useState(false);
76+
const resetTimer = useRef(null);
77+
78+
useEffect(() => () => clearTimeout(resetTimer.current), []);
79+
80+
/* Fallback for when the async Clipboard API is unavailable or refused: it needs
81+
a secure context, and browsers decline it when the document is not focused.
82+
A throwaway textarea and execCommand works in those cases -- it is what
83+
Docusaurus's own copy button relies on. */
84+
function copyViaTextarea(text) {
85+
const field = document.createElement('textarea');
86+
field.value = text;
87+
field.setAttribute('readonly', '');
88+
field.style.position = 'fixed';
89+
field.style.opacity = '0';
90+
document.body.appendChild(field);
91+
field.select();
92+
let ok = false;
93+
try {
94+
ok = document.execCommand('copy');
95+
} catch {
96+
ok = false;
97+
}
98+
document.body.removeChild(field);
99+
return ok;
100+
}
101+
102+
async function copy(event) {
103+
event.currentTarget.blur();
104+
let ok = false;
105+
try {
106+
await navigator.clipboard.writeText(active.command);
107+
ok = true;
108+
} catch {
109+
ok = copyViaTextarea(active.command);
110+
}
111+
/* Only confirm a copy that actually happened. If both routes fail the label
112+
stays put rather than claiming something untrue -- the whole command is on
113+
screen and can still be selected by hand. */
114+
if (!ok) {
115+
return;
116+
}
117+
setCopied(true);
118+
clearTimeout(resetTimer.current);
119+
resetTimer.current = setTimeout(() => setCopied(false), 2000);
120+
}
121+
122+
return (
123+
<div className={styles.wrapper}>
124+
<div className={styles.bar}>
125+
<div className={styles.tabs} role="tablist" aria-label="Operating system">
126+
{PLATFORMS.map((p) => (
127+
<button
128+
key={p.id}
129+
type="button"
130+
role="tab"
131+
aria-selected={p.id === active.id}
132+
className={clsx(styles.tab, p.id === active.id && styles.tabActive)}
133+
onClick={() => setPlatform(p.id)}>
134+
{p.label}
135+
</button>
136+
))}
137+
</div>
138+
<button
139+
type="button"
140+
className={clsx(styles.copy, copied && styles.copied)}
141+
onClick={copy}
142+
aria-label={`Copy the ${active.label} install command`}>
143+
{copied ? <CheckIcon /> : <CopyIcon />}
144+
{copied ? 'Copied' : 'Copy'}
145+
</button>
146+
</div>
147+
<CodeBlock language={active.language}>{active.command}</CodeBlock>
148+
</div>
149+
);
150+
}

0 commit comments

Comments
 (0)