Added Map View queries to the CLI and skill

This commit is contained in:
Erez Shermer 2026-04-18 10:15:51 +03:00
parent 2877a9849b
commit 96ab9a7220
4 changed files with 112 additions and 3 deletions

View file

@ -103,6 +103,37 @@ Descent: 8 m
Returns routed distance, estimated travel time, and elevation change. Does not return the path geometry.
### `mv-query`
Return all map markers that match a Map View query expression. Supports the full Map View query language — the same syntax used in the map's filter bar.
```bash
obsidian mv-query query="tag:#hiking"
```
The `query` parameter is optional. Omitting it returns every marker in the vault.
Example output:
```
1. Sentier des Crêtes [48.01230, 7.07845] (Hikes/Vosges.md)
2. Lac Blanc [47.99501, 7.05312] (Hikes/Vosges.md)
3. Cascade du Tennbach [48.00812, 7.06631] (Hikes/Alsace.md)
```
Each line contains the marker's display name, coordinates, and the path of the source note.
**Query syntax examples:**
| Query | Meaning |
| ------------------------------ | ----------------------------------------------- |
| `tag:#hiking` | Markers tagged `#hiking` |
| `path:France` | Markers from notes whose path contains "France" |
| `tag:#cafe AND path:Paris` | Cafés in Paris notes |
| `name:Louvre` | Markers whose display name contains "Louvre" |
| `tag:#restaurant OR tag:#cafe` | Restaurants or cafés |
| _(empty)_ | All markers |
### `mv-focus-note`
Focus a note in Map View, filtering the map to show only its locations.

View file

@ -1,6 +1,6 @@
---
name: map-view
description: Look up and record geolocations in Obsidian notes using the Map View plugin. Use as part of helping the user to plan a trip, research places to visit, record a location in a note, or whenever the content being added to a note includes named real-world places. Every time the user asks you add to a note something that is a location, consider using this skill so it will be logged as a geolocation. Another usage is to measure distances, either aerial or by routing (foot/driving/cycling etc), e.g. for researching for places that are nearby a location, within a walking distance from it, etc.
description: Look up and record geolocations in Obsidian notes using the Map View plugin. Use as part of helping the user to plan a trip, research places to visit, record a location in a note, or whenever the content being added to a note includes named real-world places. Every time the user asks you add to a note something that is a location, consider using this skill so it will be logged as a geolocation. Also use when the user refers to a known place ("my home", "my office", "my hotel") — query their vault to find its coordinates, then use those for distance or routing calculations. Another usage is to measure distances, either aerial or by routing (foot/driving/cycling etc), e.g. for researching for places that are nearby a location, within a walking distance from it, within a driving distance, etc.
---
# Map View
@ -40,6 +40,21 @@ Opens Map View filtered to show only the locations in that note. Use after addin
Consider actively asking the user if he wants to see the results after adding geolocations.
```bash
obsidian mv-query query="<query>"
```
Returns all map markers that match a Map View query. The `query` parameter is optional — omitting it returns every marker in the vault. Supports the full Map View query language: `tag:`, `path:`, `name:`, `linkedto:`, `linkedfrom:`, `AND`, `OR`, `NOT`, and more. Each result line contains: display name, coordinates, and source note path.
Example output:
```
1. Eiffel Tower [48.85837, 2.29450] (Places/Paris.md)
2. Louvre Museum [48.86013, 2.33552] (Places/Paris.md)
```
Use this command to query the user's vault for known locations. When the user refers to a place they have recorded ("my home", "my office", "the hotel from last week"), search the vault with `mv-query` to retrieve its coordinates — then feed those into `mv-calc-distance` or `mv-calc-route`. Also useful to find existing locations before adding new ones, or to check what's already in a note. The command initializes the layer cache automatically — no map needs to be open.
```bash
obsidian mv-calc-distance from="lat,lng" to="lat,lng"
```
@ -88,6 +103,24 @@ User asks: _"Is the hotel within 20 minutes' drive of the conference center?"_
obsidian mv-calc-route from="48.8584,2.2945" to="48.8738,2.2950" profile="car"
```
**Example: distance from existing vault markers**
User asks: _"Which restaurants in my vault are within a 15-minute walk of my hotel?"_
1. Find the hotel's coordinates using `mv-query`:
```bash
obsidian mv-query query="name:Grand Hotel"
```
2. Get all restaurant markers:
```bash
obsidian mv-query query="tag:#restaurant"
```
3. Check walking time for each candidate with `mv-calc-route` (profile `foot`). Only keep results ≤ 15 min.
**Example: quick aerial check before routing**
If you need to filter a long list of candidates, first use `mv-calc-distance` to discard obviously far-away results (e.g. > 5 km aerial for a 10-min walk), then run `mv-calc-route` only for the remaining candidates to avoid unnecessary API calls.

View file

@ -2,9 +2,16 @@ import { App, Plugin, TFile } from 'obsidian';
import * as leaflet from 'leaflet';
import { GeoSearcher } from 'src/geosearch';
import { calcRoute } from 'src/routing';
import { Query } from 'src/query';
import { FileMarker } from 'src/fileMarker';
import type { LayerCache } from 'src/layerCache';
import type { PluginSettings } from 'src/settings';
type MapViewPlugin = Plugin & { focusNoteInMap: (file: TFile) => void };
type MapViewPlugin = Plugin & {
focusNoteInMap: (file: TFile) => void;
waitForInitialization: () => Promise<void>;
layerCache: LayerCache | null;
};
export function registerCliHandlers(
plugin: MapViewPlugin,
@ -150,6 +157,44 @@ export function registerCliHandlers(
},
);
plugin.registerCliHandler(
'mv-query',
'Return all map markers matching a Map View query (full query language supported). An empty query returns all markers. Waits up to 10 seconds for the layer cache to initialize if needed.',
{
query: {
value: '<query>',
description:
'Map View query expression, e.g. tag:#hiking, path:trips, tag:#cafe AND path:Paris. Leave empty to return all markers.',
required: false,
},
},
async (params: { query?: string }) => {
// Support positional arg: `mv-query tag:#foo` arrives as {"tag:#foo": "true"}
const queryStr =
params.query ??
Object.keys(params).find((k) => k !== 'query') ??
'';
await plugin.waitForInitialization();
const query = new Query(app, queryStr);
const results: string[] = [];
let index = 1;
for (const layer of plugin.layerCache.layers) {
if (!(layer instanceof FileMarker)) continue;
if (!query.testLayer(layer)) continue;
const coords = `[${layer.location.lat.toFixed(5)}, ${layer.location.lng.toFixed(5)}]`;
results.push(
`${index}. ${layer.name} ${coords} (${layer.file.path})`,
);
index++;
}
if (!results.length)
return queryStr
? `No markers matched: ${queryStr}`
: 'No markers found in the vault.';
return results.join('\n');
},
);
function parseLatLng(str: string): leaflet.LatLng | null {
const cleaned = str.replace(/[\[\]\s]/g, '');
const m = cleaned.match(/^(-?\d+\.?\d*),(-?\d+\.?\d*)$/);

View file

@ -185,7 +185,7 @@ export class Query {
);
} else
throw new Error(
`Unsupported query format for Map View display rule: "${value}"`,
`Unsupported query format for Map View: "${value}"`,
);
}
}