diff --git a/.github/workflows/deploy-web.yaml b/.github/workflows/deploy-web.yaml index ef7c969..e64b6ed 100644 --- a/.github/workflows/deploy-web.yaml +++ b/.github/workflows/deploy-web.yaml @@ -20,7 +20,7 @@ jobs: with: python-version: "3.12" - name: Install Hatch - run: pip install hatch==1.15.1 + run: pip install hatch - uses: actions/cache@v4 with: key: mkdocs-${{ github.ref }} diff --git a/.sourcery.yaml b/.sourcery.yaml deleted file mode 100644 index 3926064..0000000 --- a/.sourcery.yaml +++ /dev/null @@ -1,3 +0,0 @@ -refactor: - skip: - - use-named-expression # Python 3.8+ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e9fef41..167feb3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -107,7 +107,7 @@ Once your device works correctly: 1. Create a branch: `git checkout -b add-device-` 2. Add your device entry to `devices.toml` -3. Test thoroughly with the examples in `examples/` +3. Test thoroughly with the examples in `examples/`. If you add a new example, update the README and `docs/mouseApi/examples.md`. 4. Submit a PR with your device name and any notes about testing ### Using Custom Configuration (Without Modifying Library) diff --git a/README.md b/README.md index a34cfb0..ab333fc 100644 --- a/README.md +++ b/README.md @@ -225,7 +225,8 @@ See the [examples/](https://github.com/JakubAndrysek/PySpaceMouse/tree/master/ex | `06_axis_callbacks.py` | Per-axis callbacks with filtering | | `07_led.py` | LED control | | `08_buttons.py` | Button names and handling | -| `09_custom_config.py` | Custom axis mappings | +| `09_invert_rotations.py` | Invert rotations | +| `10_custom_config_unity.py` | A totally custom device config using the Unity axis convention | ## Dependencies @@ -260,8 +261,9 @@ This project includes a `Makefile` with commands for creating a virtual environm You will need `hatch` and `pre-commit` for this. You can get these by using -``` -pipx install hatch==1.15.1 pre-commit +```bash +# Most recently tested with hatch 1.17.0 +pipx install hatch pre-commit ``` If you're not familiar with pipx, it lets you install python tools into isolated environments in `~/.local`. diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index e9fef41..167feb3 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -107,7 +107,7 @@ Once your device works correctly: 1. Create a branch: `git checkout -b add-device-` 2. Add your device entry to `devices.toml` -3. Test thoroughly with the examples in `examples/` +3. Test thoroughly with the examples in `examples/`. If you add a new example, update the README and `docs/mouseApi/examples.md`. 4. Submit a PR with your device name and any notes about testing ### Using Custom Configuration (Without Modifying Library) diff --git a/docs/README.md b/docs/README.md index 0733fd1..5dd34ea 100644 --- a/docs/README.md +++ b/docs/README.md @@ -133,8 +133,8 @@ with pyspacemouse.open(axis_convention=AxisConvention.HID_Z_UP) as device: ```

- Raw HID axis convention HID Z-up axis convention + Raw HID axis convention Legacy PySpaceMouse axis convention

@@ -225,7 +225,8 @@ See the [examples/](https://github.com/JakubAndrysek/PySpaceMouse/tree/master/ex | `06_axis_callbacks.py` | Per-axis callbacks with filtering | | `07_led.py` | LED control | | `08_buttons.py` | Button names and handling | -| `09_custom_config.py` | Custom axis mappings | +| `09_invert_rotations.py` | Invert rotations | +| `10_custom_config_unity.py` | A totally custom device config using the Unity axis convention | ## Dependencies @@ -260,8 +261,9 @@ This project includes a `Makefile` with commands for creating a virtual environm You will need `hatch` and `pre-commit` for this. You can get these by using -``` -pipx install hatch==1.15.1 pre-commit +```bash +# Most recently tested with hatch 1.17.0 +pipx install hatch pre-commit ``` If you're not familiar with pipx, it lets you install python tools into isolated environments in `~/.local`. diff --git a/docs/assets/hid_axes.svg b/docs/assets/hid_axes.svg index 775cea2..be48db7 100644 --- a/docs/assets/hid_axes.svg +++ b/docs/assets/hid_axes.svg @@ -459,4 +459,4 @@ - \ No newline at end of file + diff --git a/docs/assets/hid_z_up_axes.svg b/docs/assets/hid_z_up_axes.svg index 6998330..65532a2 100644 --- a/docs/assets/hid_z_up_axes.svg +++ b/docs/assets/hid_z_up_axes.svg @@ -453,4 +453,4 @@ - \ No newline at end of file + diff --git a/docs/assets/legacy_axis.svg b/docs/assets/legacy_axis.svg index 9ac7c08..7f1f099 100644 --- a/docs/assets/legacy_axis.svg +++ b/docs/assets/legacy_axis.svg @@ -445,4 +445,4 @@ - \ No newline at end of file + diff --git a/docs/mouseApi/examples.md b/docs/mouseApi/examples.md index aecea91..8bdea96 100644 --- a/docs/mouseApi/examples.md +++ b/docs/mouseApi/examples.md @@ -1,96 +1,101 @@ # Examples +## 01. Basic -## Basic usage -[basicExample.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/basicExample.py) -````py -import pyspacemouse -import time +- File: [01_basic.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/01_basic.py) +- Summary: Basic example: Read SpaceMouse input with context manager. +- Run: `python examples/01_basic.py` -success = pyspacemouse.open() -if success: - while 1: - state = pyspacemouse.read() - print(state.x, state.y, state.z) - time.sleep(0.01) -```` +```py title="examples/01_basic.py" +--8<-- "examples/01_basic.py" +``` +## 02. Callbacks -## Usage with callback -[callbackExample.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/callbackExample.py) -````py -import pyspacemouse -import time +- File: [02_callbacks.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/02_callbacks.py) +- Summary: Callbacks example: React to button presses and axis movements. +- Run: `python examples/02_callbacks.py` +```py title="examples/02_callbacks.py" +--8<-- "examples/02_callbacks.py" +``` -def button_0(state, buttons, pressed_buttons): - print("Button:", pressed_buttons) +## 03. Multi Device +- File: [03_multi_device.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/03_multi_device.py) +- Summary: Multi-device example: Connect to multiple SpaceMouse devices. +- Run: `python examples/03_multi_device.py` -def button_0_1(state, buttons, pressed_buttons): - print("Buttons:", pressed_buttons) +```py title="examples/03_multi_device.py" +--8<-- "examples/03_multi_device.py" +``` +## 04. Open By Path -def someButton(state, buttons): - print("Some button") +- File: [04_open_by_path.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/04_open_by_path.py) +- Summary: Open by path example: Connect to a specific HID device by filesystem path. +- Run: `python examples/04_open_by_path.py` +```py title="examples/04_open_by_path.py" +--8<-- "examples/04_open_by_path.py" +``` -def callback(): - button_arr = [pyspacemouse.ButtonCallback(0, button_0), - pyspacemouse.ButtonCallback([1], lambda state, buttons, pressed_buttons: print("Button: 1")), - pyspacemouse.ButtonCallback([0, 1], button_0_1), ] +## 05. Discovery - success = pyspacemouse.open(dof_callback=pyspacemouse.print_state, button_callback=someButton, - button_callback_arr=button_arr) - if success: - while True: - pyspacemouse.read() - time.sleep(0.01) +- File: [05_discovery.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/05_discovery.py) +- Summary: Device discovery example: List and inspect available devices. +- Run: `python examples/05_discovery.py` +```py title="examples/05_discovery.py" +--8<-- "examples/05_discovery.py" +``` -if __name__ == '__main__': - callback() -```` +## 06. Axis Callbacks +- File: [06_axis_callbacks.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/06_axis_callbacks.py) +- Summary: Axis callbacks example: React to specific axis movements. +- Run: `python examples/06_axis_callbacks.py` -### Callback: print_state +```py title="examples/06_axis_callbacks.py" +--8<-- "examples/06_axis_callbacks.py" +``` -Print all axis states +## 07. Led - x +0.00 y +0.00 z +0.00 roll +0.00 pitch +0.00 yaw +0.00 t +0.0 +- File: [07_led.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/07_led.py) +- Summary: LED control example: Blink the SpaceMouse LED. +- Run: `python examples/07_led.py` -### Callback: print_buttons +```py title="examples/07_led.py" +--8<-- "examples/07_led.py" +``` -Print all buttons states +## 08. Buttons - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ] +- File: [08_buttons.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/08_buttons.py) +- Summary: Button names example: Show button names when pressed. +- Run: `python examples/08_buttons.py` +```py title="examples/08_buttons.py" +--8<-- "examples/08_buttons.py" +``` -## Custom Device Configuration +## 09. Invert Rotations -[09_custom_config.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/09_custom_config.py) +- File: [09_invert_rotations.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/09_invert_rotations.py) +- Summary: Example: Invert rotation axes +- Run: `python examples/09_invert_rotations.py` -Customize axis mappings for different coordinate conventions (ROS, OpenGL, etc.): +```py title="examples/09_invert_rotations.py" +--8<-- "examples/09_invert_rotations.py" +``` -````py -import pyspacemouse +## 10. Custom Config Unity -# Get existing device spec and modify it -specs = pyspacemouse.get_device_specs() -base = specs["SpaceNavigator"] +- File: [10_custom_config_unity.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/10_custom_config_unity.py) +- Summary: Example: Custom device configuration with axis remapping. +- Run: `python examples/10_custom_config_unity.py` -# Invert axes for ROS conventions -ros_spec = pyspacemouse.modify_device_info( - base, - name="SpaceNavigator (ROS)", - invert_axes=["y", "z", "roll", "yaw"], -) - -# Open with custom configuration -with pyspacemouse.open(device_spec=ros_spec) as device: - while True: - state = device.read() - print(f"x={state.x:.2f} y={state.y:.2f} z={state.z:.2f}") -```` - -See also: `create_device_info()` for creating completely custom device specs. +```py title="examples/10_custom_config_unity.py" +--8<-- "examples/10_custom_config_unity.py" +``` diff --git a/examples/01_basic.py b/examples/01_basic.py index 550733d..11c3db4 100644 --- a/examples/01_basic.py +++ b/examples/01_basic.py @@ -5,9 +5,10 @@ """ import pyspacemouse +from pyspacemouse import AxisConvention # Using context manager (recommended) -with pyspacemouse.open() as device: +with pyspacemouse.open(axis_convention=AxisConvention.HID_Z_UP) as device: print(f"Connected to: {device.name}") print("Move the SpaceMouse to see values (Ctrl+C to exit)") diff --git a/examples/02_callbacks.py b/examples/02_callbacks.py index f30175c..776997e 100644 --- a/examples/02_callbacks.py +++ b/examples/02_callbacks.py @@ -8,6 +8,7 @@ import time import pyspacemouse +from pyspacemouse import AxisConvention # Button callbacks receive (state, buttons, pressed_buttons) @@ -39,6 +40,7 @@ def on_any_button(state, buttons): # Open with callbacks with pyspacemouse.open( + axis_convention=AxisConvention.HID_Z_UP, dof_callback=pyspacemouse.print_state, # Built-in DOF printer button_callback=on_any_button, button_callbacks=button_callbacks, diff --git a/examples/03_multi_device.py b/examples/03_multi_device.py index a027323..98cd699 100644 --- a/examples/03_multi_device.py +++ b/examples/03_multi_device.py @@ -7,6 +7,7 @@ import time import pyspacemouse +from pyspacemouse import AxisConvention def main(): @@ -24,8 +25,10 @@ def main(): path1 = list(connected.keys())[1] # Open two devices by path - with pyspacemouse.open_by_path(path0) as left_hand: - with pyspacemouse.open_by_path(path1) as right_hand: + with pyspacemouse.open_by_path(path0, axis_convention=AxisConvention.HID_Z_UP) as left_hand: + with pyspacemouse.open_by_path( + path1, axis_convention=AxisConvention.HID_Z_UP + ) as right_hand: print(f"Left hand: {left_hand.name}") print(f"Right hand: {right_hand.name}") print() diff --git a/examples/04_open_by_path.py b/examples/04_open_by_path.py index f1af695..2425cc5 100644 --- a/examples/04_open_by_path.py +++ b/examples/04_open_by_path.py @@ -10,6 +10,7 @@ """ import pyspacemouse +from pyspacemouse import AxisConvention def main(): @@ -25,7 +26,10 @@ def main(): device_path = "/dev/hidraw0" try: - with pyspacemouse.open_by_path(device_path) as device: + with pyspacemouse.open_by_path( + device_path, + axis_convention=AxisConvention.HID_Z_UP, + ) as device: print(f"Connected to: {device.name} at {device_path}") print("Move the device (Ctrl+C to exit)") print() diff --git a/examples/06_axis_callbacks.py b/examples/06_axis_callbacks.py index 9aebd6a..02f5e63 100644 --- a/examples/06_axis_callbacks.py +++ b/examples/06_axis_callbacks.py @@ -9,6 +9,7 @@ import time import pyspacemouse +from pyspacemouse import AxisConvention def on_x_positive(state, value): @@ -46,7 +47,10 @@ def on_z_move(state, value): ), ] -with pyspacemouse.open(dof_callbacks=dof_callbacks) as device: +with pyspacemouse.open( + dof_callbacks=dof_callbacks, + axis_convention=AxisConvention.HID_Z_UP, +) as device: print(f"Connected to: {device.name}") print("Move X axis (left/right) or Z axis (up/down)") print("Ctrl+C to exit") diff --git a/examples/07_led.py b/examples/07_led.py index b68e882..00edf48 100644 --- a/examples/07_led.py +++ b/examples/07_led.py @@ -9,9 +9,10 @@ import time import pyspacemouse +from pyspacemouse import AxisConvention # Using context manager (recommended) -with pyspacemouse.open() as device: +with pyspacemouse.open(axis_convention=AxisConvention.HID_Z_UP) as device: print(f"Connected to: {device.name}") print("LED will blink every 0.5 seconds (Ctrl+C to exit)") print() diff --git a/examples/08_buttons.py b/examples/08_buttons.py index c998a5a..ecf27ac 100644 --- a/examples/08_buttons.py +++ b/examples/08_buttons.py @@ -7,6 +7,7 @@ import time import pyspacemouse +from pyspacemouse import AxisConvention def on_button_change(state, buttons): @@ -21,7 +22,10 @@ def on_button_change(state, buttons): # Open device -with pyspacemouse.open(button_callback=on_button_change) as device: +with pyspacemouse.open( + button_callback=on_button_change, + axis_convention=AxisConvention.HID_Z_UP, +) as device: print(f"Connected to: {device.name}") print(f"Device has {len(device.info.button_names)} buttons:") for i, name in enumerate(device.info.button_names): diff --git a/examples/09_custom_config.py b/examples/09_custom_config.py deleted file mode 100644 index 02279d7..0000000 --- a/examples/09_custom_config.py +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env python3 -"""Example: Custom device configuration with axis remapping. - -This example shows how to: -1. Get existing device specs -2. Modify axis directions for ROS/other conventions -3. Create entirely custom device configurations -""" - -import time - -import pyspacemouse - - -def example_modify_existing(): - """Modify an existing device spec to invert axes.""" - print("=" * 60) - print("Example 1: Modify existing device spec") - print("=" * 60) - - # Get all device specs from TOML - specs = pyspacemouse.get_device_specs() - print(f"Available devices: {list(specs.keys())}") - - # Get connected devices - connected = pyspacemouse.get_connected_devices_by_path() - if not connected: - print("No devices connected!") - return - if len(connected) > 1: - print("This example only works with one device connected.") - return - - device_name = list(connected.values())[0] - print(f"Using device: {device_name}") - - # Get base spec and create modified version - base_spec = specs[device_name] - print(f"Original mappings: y scale = {base_spec.mappings['y'].scale}") - - # Create modified spec with inverted Y and Z (common for ROS) - ros_spec = pyspacemouse.modify_device_info( - base_spec, - name=f"{device_name} (ROS)", - invert_axes=["y", "z"], # Invert these axes - ) - print(f"Modified mappings: y scale = {ros_spec.mappings['y'].scale}") - - # Open with custom spec - with pyspacemouse.open(device_spec=ros_spec) as device: - print(f"\nConnected to: {device.name}") - print("Move the SpaceMouse (Ctrl+C to exit)") - print("Y and Z axes are now inverted!\n") - - for _ in range(500): # Run for ~5 seconds - state = device.read() - if state.has_motion(): - print(f"x={state.x:+.2f} y={state.y:+.2f} z={state.z:+.2f} (Y/Z inverted)") - time.sleep(0.01) - - -def example_invert_rotations(): - """Show how to fix rotation axes for specific conventions.""" - print("\n" + "=" * 60) - print("Example 2: Fix rotation conventions") - print("=" * 60) - - connected = pyspacemouse.get_connected_devices_by_path() - if not connected: - print("No devices connected!") - return - if len(connected) > 1: - print("This example only works with one device connected.") - return - - device_name = list(connected.values())[0] - specs = pyspacemouse.get_device_specs() - base_spec = specs[device_name] - - # Invert roll and yaw for right-handed coordinate system - fixed_spec = pyspacemouse.modify_device_info( - base_spec, - name=f"{device_name} (Fixed Rotations)", - invert_axes=["roll", "yaw"], - ) - - with pyspacemouse.open(device_spec=fixed_spec) as device: - print(f"Connected to: {device.name}") - print("Roll and Yaw are now inverted!\n") - - for _ in range(500): - state = device.read() - if state.has_motion(): - print(f"roll={state.roll:+.2f} pitch={state.pitch:+.2f} yaw={state.yaw:+.2f}") - time.sleep(0.01) - - -def example_create_custom(): - """Create entirely custom device configuration.""" - print("\n" + "=" * 60) - print("Example 3: Create custom device spec (reference)") - print("=" * 60) - - # This shows how to create a completely custom device spec - # Useful for unsupported devices or complete remapping - custom_spec = pyspacemouse.create_device_info( - name="CustomSpaceMouse", - vendor_id=0x256F, # 3Dconnexion - product_id=0xC635, # SpaceMouse Compact - mappings={ - # Each mapping: (channel, byte1, byte2, scale) - # Scale: 1 = normal direction, -1 = inverted - "x": (1, 1, 2, 1), - "y": (1, 3, 4, 1), # NOT inverted (unlike default) - "z": (1, 5, 6, 1), # NOT inverted (unlike default) - "pitch": (2, 1, 2, 1), # NOT inverted - "roll": (2, 3, 4, 1), # NOT inverted - "yaw": (2, 5, 6, 1), - }, - buttons={ - "LEFT": (3, 1, 0), - "RIGHT": (3, 1, 1), - }, - ) - - print(f"Created custom spec: {custom_spec.name}") - print(f" VID/PID: {custom_spec.vendor_id:#06x}/{custom_spec.product_id:#06x}") - print(f" Axes: {list(custom_spec.mappings.keys())}") - print(f" Buttons: {custom_spec.button_names}") - print("\n (Not opening - this is just to show the API)") - - -if __name__ == "__main__": - try: - example_modify_existing() - example_invert_rotations() - example_create_custom() - except KeyboardInterrupt: - print("\nExiting...") diff --git a/examples/09_invert_rotations.py b/examples/09_invert_rotations.py new file mode 100644 index 0000000..b42d0f4 --- /dev/null +++ b/examples/09_invert_rotations.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +"""Example: Inverting rotations + +This example shows how to invert axes, in this case the rotation axes (roll, pitch, yaw). +Just for demonstration purposes, this would be pretty weird :) +""" + +import time + +import pyspacemouse +from pyspacemouse import AxisConvention + + +def example_invert_rotations(): + """Show how to invert rotation axes""" + print("\n" + "=" * 60) + print("Invert rotations") + print("=" * 60) + + connected = pyspacemouse.get_connected_devices() + if not connected: + print("No devices connected!") + return + + specs = pyspacemouse.get_device_specs() + base_spec_legacy = specs[connected[0]] + base_spec = pyspacemouse.apply_axis_convention(base_spec_legacy, AxisConvention.HID_Z_UP) + + # Invert roll, pitch, and yaw + fixed_spec = pyspacemouse.modify_device_info( + base_spec, + name=f"{connected[0]} (Fixed Rotations)", + # Translation axes (x, y, z) can also be inverted here + invert_axes=["roll", "pitch", "yaw"], + ) + + with pyspacemouse.open(device_spec=fixed_spec) as device: + print(f"Connected to: {device.name}") + print("Rotations are now inverted!\n") + + for _ in range(500): + state = device.read() + if any([state.roll, state.pitch, state.yaw]): + print( + f"x={state.x:+.2f} y={state.y:+.2f} z={state.z:+.2f} " + f"roll={state.roll:+.2f} pitch={state.pitch:+.2f} yaw={state.yaw:+.2f}" + ) + time.sleep(0.01) + + +if __name__ == "__main__": + try: + example_invert_rotations() + except KeyboardInterrupt: + print("\nExiting...") diff --git a/examples/10_custom_config_unity.py b/examples/10_custom_config_unity.py new file mode 100644 index 0000000..aefc7c7 --- /dev/null +++ b/examples/10_custom_config_unity.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +"""Example: Custom device configuration + +This example shows how to create entirely custom device configurations, +In this case for a "Spacemouse Wireless New", following the left-handed Unity convention (Z forward, X right, Y up). +If you have a totally custom HID device, you just need to know the byte layout of the device and you can create a custom configuration for it. +""" + +import time + +import pyspacemouse + + +def example_unity_convention(): + """Create entirely custom device configuration with the Unity convention.""" + print("\n" + "=" * 60) + print("Create custom device spec (Unity convention)") + print("=" * 60) + + # This shows how to create a completely custom device spec + # Useful for unsupported devices or complete remapping + custom_spec = pyspacemouse.create_device_info( + name="CustomSpaceMouse", + vendor_id=0x256F, # 3Dconnexion + product_id=0xC63A, # SpaceMouse Wireless New + mappings={ + # Each mapping: (channel, byte1, byte2, scale) + # Scale: 1 = normal direction, -1 = inverted + "x": (1, 1, 2, 1), + "y": (1, 5, 6, -1), + "z": (1, 3, 4, -1), + "yaw": (1, 9, 10, 1), + "pitch": (1, 11, 12, 1), + "roll": (1, 7, 8, -1), + }, + buttons={ + "LEFT": (3, 1, 0), + "RIGHT": (3, 1, 1), + }, + ) + + print(f"Created custom Unity spec: {custom_spec.name}") + print(f" VID/PID: {custom_spec.vendor_id:#06x}/{custom_spec.product_id:#06x}") + print(f" Axes: {list(custom_spec.mappings.keys())}") + print(f" Buttons: {custom_spec.button_names}") + + with pyspacemouse.open(device_spec=custom_spec) as device: + print(f"Connected to: {device.name} with custom spec") + + for _ in range(5000): + state = device.read() + if any([state.x, state.y, state.z, state.roll, state.pitch, state.yaw]): + print( + f"x={state.x:+.2f} y={state.y:+.2f} z={state.z:+.2f} " + f"roll={state.roll:+.2f} pitch={state.pitch:+.2f} yaw={state.yaw:+.2f}" + ) + time.sleep(0.01) + + +if __name__ == "__main__": + try: + example_unity_convention() + except KeyboardInterrupt: + print("\nExiting...") diff --git a/mkdocs.yml b/mkdocs.yml index 10c4657..73fd5dd 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -90,6 +90,8 @@ plugins: markdown_extensions: - pymdownx.highlight - pymdownx.superfences + - pymdownx.snippets: + check_paths: true - admonition - pymdownx.details - pymdownx.superfences