Index: /trunk/src/org/openstreetmap/josm/io/NameFinder.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/NameFinder.java	(revision 11002)
+++ /trunk/src/org/openstreetmap/josm/io/NameFinder.java	(revision 11003)
@@ -14,4 +14,7 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
 import org.openstreetmap.josm.tools.HttpClient;
 import org.openstreetmap.josm.tools.OsmUrlToBounds;
@@ -67,4 +70,5 @@
         public int zoom;
         public Bounds bounds;
+        public PrimitiveId osmId;
 
         public Bounds getDownloadArea() {
@@ -127,4 +131,9 @@
                             Double.parseDouble(bbox[0]), Double.parseDouble(bbox[2]),
                             Double.parseDouble(bbox[1]), Double.parseDouble(bbox[3]));
+                    final String osmId = atts.getValue("osm_id");
+                    final String osmType = atts.getValue("osm_type");
+                    if (osmId != null && osmType != null) {
+                        currentResult.osmId = new SimplePrimitiveId(Long.parseLong(osmId), OsmPrimitiveType.from(osmType));
+                    }
                     data.add(currentResult);
                 }
Index: /trunk/src/org/openstreetmap/josm/io/OverpassDownloadReader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/OverpassDownloadReader.java	(revision 11002)
+++ /trunk/src/org/openstreetmap/josm/io/OverpassDownloadReader.java	(revision 11003)
@@ -4,5 +4,8 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.io.IOException;
 import java.io.InputStream;
+import java.util.EnumMap;
+import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -11,9 +14,13 @@
 import javax.xml.stream.XMLStreamException;
 
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.DataSource;
 import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.tools.HttpClient;
+import org.openstreetmap.josm.tools.UncheckedParseException;
 import org.openstreetmap.josm.tools.Utils;
 
@@ -51,40 +58,46 @@
             return super.getRequestForBbox(lon1, lat1, lon2, lat2);
         else {
-            String realQuery = completeOverpassQuery(overpassQuery);
-            return "interpreter?data=" + Utils.encodeUrl(realQuery)
-                    + "&bbox=" + lon1 + ',' + lat1 + ',' + lon2 + ',' + lat2;
+            final String overpassQuery = this.overpassQuery.replace("{{bbox}}", lat1 + "," + lon1 + "," + lat2 + "," + lon2);
+            final String expandedOverpassQuery = expandExtendedQueries(overpassQuery);
+            return "interpreter?data=" + Utils.encodeUrl(expandedOverpassQuery);
         }
     }
 
-    private static String completeOverpassQuery(String query) {
-        int firstColon = query.indexOf(';');
-        if (firstColon == -1) {
-            return "[bbox];" + query;
-        }
-        int bboxPos = query.indexOf("[bbox");
-        if (bboxPos > -1 && bboxPos < firstColon) {
-            return query;
-        }
-
-        int bracketCount = 0;
-        int pos = 0;
-        for (; pos < firstColon; ++pos) {
-            if (query.charAt(pos) == '[')
-                ++bracketCount;
-            else if (query.charAt(pos) == ']')
-                --bracketCount;
-            else if (bracketCount == 0) {
-                if (!Character.isWhitespace(query.charAt(pos)))
-                    break;
+    /**
+     * Evaluates some features of overpass turbo extended query syntax.
+     * See https://wiki.openstreetmap.org/wiki/Overpass_turbo/Extended_Overpass_Turbo_Queries
+     */
+    static String expandExtendedQueries(String query) {
+        final StringBuffer sb = new StringBuffer();
+        final Matcher matcher = Pattern.compile("\\{\\{(geocodeArea):([^}]+)\\}\\}").matcher(query);
+        while (matcher.find()) {
+            try {
+                switch (matcher.group(1)) {
+                    case "geocodeArea":
+                        matcher.appendReplacement(sb, geocodeArea(matcher.group(2)));
+                }
+            } catch (Exception ex) {
+                final String msg = tr("Failed to evaluate {0}", matcher.group());
+                Main.warn(ex, msg);
+                matcher.appendReplacement(sb, "// " + msg + "\n");
             }
         }
+        matcher.appendTail(sb);
+        return sb.toString();
+    }
 
-        if (pos < firstColon) {
-            // We start with a statement, not with declarations
-            return "[bbox];" + query;
+    private static String geocodeArea(String area) {
+        // Offsets defined in https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL#By_element_id
+        final EnumMap<OsmPrimitiveType, Long> idOffset = new EnumMap<>(OsmPrimitiveType.class);
+        idOffset.put(OsmPrimitiveType.NODE, 0L);
+        idOffset.put(OsmPrimitiveType.WAY, 2400000000L);
+        idOffset.put(OsmPrimitiveType.RELATION, 3600000000L);
+        try {
+            final List<NameFinder.SearchResult> results = NameFinder.queryNominatim(area);
+            final PrimitiveId osmId = results.iterator().next().osmId;
+            return String.format("area(%d)", osmId.getUniqueId() + idOffset.get(osmId.getType()));
+        } catch (IOException ex) {
+            throw new UncheckedParseException(ex);
         }
-
-        // We start with declarations. Add just one more declaration in this case.
-        return "[bbox]" + query;
     }
 
@@ -150,5 +163,5 @@
 
         // add bounds if necessary (note that Overpass API does not return bounds in the response XML)
-        if (ds != null && ds.dataSources.isEmpty()) {
+        if (ds != null && ds.dataSources.isEmpty() && overpassQuery.contains("{{bbox}}")) {
             if (crosses180th) {
                 Bounds bounds = new Bounds(lat1, lon1, lat2, 180.0);
Index: /trunk/src/org/openstreetmap/josm/tools/OverpassTurboQueryWizard.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/OverpassTurboQueryWizard.java	(revision 11002)
+++ /trunk/src/org/openstreetmap/josm/tools/OverpassTurboQueryWizard.java	(revision 11003)
@@ -70,9 +70,5 @@
                 throw new UncheckedParseException();
             }
-            String query = (String) result;
-            if (query != null) {
-                query = query.replace("[bbox:{{bbox}}]", "");
-            }
-            return query;
+            return (String) result;
         } catch (NoSuchMethodException e) {
             throw new IllegalStateException(e);
Index: /trunk/test/unit/org/openstreetmap/josm/io/OverpassDownloadReaderTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/io/OverpassDownloadReaderTest.java	(revision 11003)
+++ /trunk/test/unit/org/openstreetmap/josm/io/OverpassDownloadReaderTest.java	(revision 11003)
@@ -0,0 +1,79 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io;
+
+import static org.junit.Assert.assertEquals;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.gui.preferences.server.OverpassServerPreference;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.tools.OverpassTurboQueryWizard;
+import org.openstreetmap.josm.tools.Utils;
+
+/**
+ * Unit tests of {@link OverpassDownloadReader} class.
+ */
+public class OverpassDownloadReaderTest {
+
+    /**
+     * Base test environment is enough
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules().timeout(15000);
+
+    private String getExpandedQuery(String search) {
+        final String query = OverpassTurboQueryWizard.getInstance().constructQuery(search);
+        final String request = new OverpassDownloadReader(new Bounds(1, 2, 3, 4), OverpassServerPreference.getOverpassServer(), query)
+                .getRequestForBbox(1, 2, 3, 4)
+                .substring("interpreter?data=".length());
+        return Utils.decodeUrl(request);
+    }
+
+    /**
+     * Tests evaluating the extended query feature {@code bbox}.
+     */
+    @Test
+    public void testBbox() {
+        final String query = getExpandedQuery("amenity=drinking_water");
+        assertEquals("" +
+                "[out:xml][timeout:25][bbox:2.0,1.0,4.0,3.0];\n" +
+                "(\n" +
+                "  node[\"amenity\"=\"drinking_water\"];\n" +
+                "  way[\"amenity\"=\"drinking_water\"];\n" +
+                "  relation[\"amenity\"=\"drinking_water\"];\n" +
+                ");\n" +
+                "(._;>;);\n" +
+                "out meta;", query);
+    }
+
+    /**
+     * Tests evaluating the extended query feature {@code geocodeArea}.
+     */
+    @Test
+    public void testGeocodeArea() {
+        final String query = getExpandedQuery("amenity=drinking_water in London");
+        assertEquals("" +
+                "[out:xml][timeout:25];\n" +
+                "area(3600065606)->.searchArea;\n" +
+                "(\n" +
+                "  node[\"amenity\"=\"drinking_water\"](area.searchArea);\n" +
+                "  way[\"amenity\"=\"drinking_water\"](area.searchArea);\n" +
+                "  relation[\"amenity\"=\"drinking_water\"](area.searchArea);\n" +
+                ");\n" +
+                "(._;>;);\n" +
+                "out meta;", query);
+    }
+
+    /**
+     * Tests evaluating the extended query feature {@code geocodeArea}.
+     */
+    @Test
+    public void testGeocodeUnknownArea() {
+        final String query = OverpassDownloadReader.expandExtendedQueries("{{geocodeArea:foo-bar-baz-does-not-exist}}");
+        assertEquals("// Failed to evaluate {{geocodeArea:foo-bar-baz-does-not-exist}}\n", query);
+    }
+
+}
Index: /trunk/test/unit/org/openstreetmap/josm/tools/OverpassTurboQueryWizardTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/tools/OverpassTurboQueryWizardTest.java	(revision 11002)
+++ /trunk/test/unit/org/openstreetmap/josm/tools/OverpassTurboQueryWizardTest.java	(revision 11003)
@@ -28,5 +28,5 @@
         final String query = OverpassTurboQueryWizard.getInstance().constructQuery("amenity=drinking_water");
         assertEquals("" +
-                "[out:xml][timeout:25];\n" +
+                "[out:xml][timeout:25][bbox:{{bbox}}];\n" +
                 "(\n" +
                 "  node[\"amenity\"=\"drinking_water\"];\n" +
