Index: trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java	(revision 2146)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java	(revision 2147)
@@ -17,8 +17,11 @@
 import javax.swing.JLabel;
 import javax.swing.JList;
+import javax.swing.JTextField;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.Scrollable;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
 
 import org.openstreetmap.josm.Main;
@@ -40,12 +43,41 @@
     private JScrollPane pluginPane;
     private PluginSelection selection = new PluginSelection();
+    private JTextField txtFilter;
 
     public void addGui(final PreferenceDialog gui) {
         this.gui = gui;
         plugin = gui.createPreferenceTab("plugin", tr("Plugins"), tr("Configure available plugins."), false);
+
+        txtFilter = new JTextField();
+        JLabel lbFilter = new JLabel(tr("Search: "));
+        lbFilter.setLabelFor(txtFilter);
+        plugin.add(lbFilter);
+        plugin.add(txtFilter, GBC.eol().fill(GBC.HORIZONTAL));
+        txtFilter.getDocument().addDocumentListener(new DocumentListener(){
+            public void changedUpdate(DocumentEvent e) {
+                action();
+            }
+
+            public void insertUpdate(DocumentEvent e) {
+                action();
+            }
+
+            public void removeUpdate(DocumentEvent e) {
+                action();
+            }
+
+            private void action() {
+                selection.drawPanel(pluginPanel);
+            }
+        });
+        plugin.add(GBC.glue(0,10), GBC.eol());
+
+        /* main plugin area */
         pluginPane = new JScrollPane(pluginPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
         pluginPane.setBorder(null);
         plugin.add(pluginPane, GBC.eol().fill(GBC.BOTH));
         plugin.add(GBC.glue(0,10), GBC.eol());
+
+        /* buttons at the bottom */
         JButton morePlugins = new JButton(tr("Download List"));
         morePlugins.addActionListener(new ActionListener(){
@@ -72,4 +104,5 @@
         plugin.add(configureSites, GBC.std());
 
+        selection.passTxtFilter(txtFilter);
         selection.drawPanel(pluginPanel);
     }
Index: trunk/src/org/openstreetmap/josm/plugins/PluginSelection.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/PluginSelection.java	(revision 2146)
+++ trunk/src/org/openstreetmap/josm/plugins/PluginSelection.java	(revision 2147)
@@ -31,4 +31,5 @@
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
+import javax.swing.JTextField;
 import javax.swing.UIManager;
 import javax.swing.event.HyperlinkEvent;
@@ -45,4 +46,11 @@
     private Map<String, PluginInformation> availablePlugins;
     private Map<String, PluginInformation> localPlugins;
+
+    private JTextField txtFilter = null;
+
+    /* Get a copy of PluginPreference's txtField so we can use it for searching */
+    public void passTxtFilter(JTextField filter) {
+        txtFilter = filter;
+    }
 
     public void updateDescription(JPanel pluginPanel) {
@@ -213,4 +221,15 @@
             }
 
+            /* If this plugin doesn't match our search parameters we don't want to display it */
+            if (txtFilter.getText() != null) {
+                boolean matches = filterNameAndDescription(txtFilter.getText(),plugin.name,
+                                                           plugin.getLinkDescription(),
+                                                           remoteversion, localversion);
+                if (!matches) {
+                    /* This is not the plugin you're looking for */
+                    continue;
+                }
+            }
+
             final JCheckBox pluginCheck = new JCheckBox(
                     tr("{0}: Version {1}{2}", plugin.name, remoteversion, localversion),
@@ -253,4 +272,29 @@
         }
         pluginPanel.updateUI();
+    }
+
+    private static boolean filterNameAndDescription(String filter, final String name, final String description,
+                                                    final String remoteversion, final String localversion) {
+        final String input[] = filter.split("\\s+");
+        /* We're doing case-insensitive matching */
+        final String name_lc = name.toLowerCase();
+        final String description_lc = description.toLowerCase();
+        final String remoteversion_lc = remoteversion.toLowerCase();
+        final String localversion_lc = localversion.toLowerCase();
+
+        boolean canHas = true;
+
+        /* Make 'foo bar' search for 'bar' or 'foo' in both name and description */
+        for (String bit : input) {
+            final String lc_bit = bit.toLowerCase();
+            if (!name_lc.contains(lc_bit) &&
+                !description_lc.contains(lc_bit) &&
+                !remoteversion_lc.contains(lc_bit) && 
+                !localversion_lc.contains(lc_bit)) {
+                canHas = false;
+            }
+        }
+
+        return canHas;
     }
 
