/* * ModeProvider.java - An edit mode provider. * :tabSize=4:indentSize=4:noTabs=false: * :folding=explicit:collapseFolds=1: * * Copyright (C) 2003 Slava Pestov * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.gjt.sp.jedit.syntax; //{{{ Imports import org.gjt.sp.jedit.Mode; import org.gjt.sp.util.IOUtilities; import org.gjt.sp.util.Log; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.LinkedHashMap; //}}} /** * This class works like a singleton, the instance is initialized by jEdit. * * @author Matthieu Casanova * @version $Id: Buffer.java 8190 2006-12-07 07:58:34Z kpouer $ * @since jEdit 4.3pre10 */ public class ModeProvider { public static ModeProvider instance = new ModeProvider(); private final LinkedHashMap<String, Mode> modes = new LinkedHashMap<String, Mode>(220); //{{{ removeAll() method public void removeAll() { modes.clear(); } //}}} //{{{ getMode() method /** * Returns the edit mode with the specified name. * @param name The edit mode * @since jEdit 4.3pre10 */ public Mode getMode(String name) { return modes.get(name); } //}}} //{{{ getModeForFile() method /** * Get the appropriate mode that must be used for the file * @param filename the filename * @param firstLine the first line of the file * @return the edit mode, or null if no mode match the file * @since jEdit 4.3pre12 */ public Mode getModeForFile(String filename, String firstLine) { return getModeForFile(null, filename, firstLine); } //}}} //{{{ getModeForFile() method /** * Get the appropriate mode that must be used for the file * @param filepath the filepath, can be {@code null} * @param filename the filename, can be {@code null} * @param firstLine the first line of the file * @return the edit mode, or null if no mode match the file * @since jEdit 4.5pre1 */ public Mode getModeForFile(String filepath, String filename, String firstLine) { if (filepath != null && filepath.endsWith(".gz")) filepath = filepath.substring(0, filepath.length() - 3); if (filename != null && filename.endsWith(".gz")) filename = filename.substring(0, filename.length() - 3); List<Mode> acceptable = new ArrayList<Mode>(1); for(Mode mode : modes.values()) { if(mode.accept(filepath, filename, firstLine)) { acceptable.add(mode); } } if (acceptable.size() == 1) { return acceptable.get(0); } if (acceptable.size() > 1) { // The check should be in reverse order so that // modes from the user catalog get checked first! Collections.reverse(acceptable); // the very most acceptable mode is one whose file // name doesn't only match the file name as regular // expression but which is identical for (Mode mode : acceptable) { if (mode.acceptIdentical(filepath, filename)) { return mode; } } // most acceptable is a mode that matches both the // filepath and the first line glob for (Mode mode : acceptable) { if (mode.acceptFile(filepath, filename) && mode.acceptFirstLine(firstLine)) { return mode; } } // next best is filepath match for (Mode mode : acceptable) { if (mode.acceptFile(filepath, filename)) { return mode; } } // all acceptable choices are by first line glob, and // they all match, so just return the first one. return acceptable.get(0); } // no matching mode found for this file return null; } //}}} //{{{ getModes() method /** * Returns an array of installed edit modes. * @since jEdit 4.3pre10 */ public Mode[] getModes() { return modes.values().toArray(new Mode[modes.size()]); } //}}} //{{{ addMode() method /** * Do not call this method. It is only public so that classes * in the org.gjt.sp.jedit.syntax package can access it. * @since jEdit 4.3pre10 * @see org.gjt.sp.jedit.jEdit#reloadModes reloadModes * @param mode The edit mode */ public void addMode(Mode mode) { String name = mode.getName(); // The removal makes the "insertion order" in modes // (LinkedHashMap) follow the order of addMode() calls. modes.remove(name); modes.put(name, mode); } //}}} //{{{ loadMode() method public void loadMode(Mode mode, XModeHandler xmh) { String fileName = (String)mode.getProperty("file"); Log.log(Log.NOTICE,this,"Loading edit mode " + fileName); XMLReader parser; try { parser = XMLReaderFactory.createXMLReader(); } catch (SAXException saxe) { Log.log(Log.ERROR, this, saxe); return; } mode.setTokenMarker(xmh.getTokenMarker()); InputStream grammar; try { grammar = new BufferedInputStream( new FileInputStream(fileName)); } catch (FileNotFoundException e1) { InputStream resource = ModeProvider.class.getResourceAsStream(fileName); if (resource == null) error(fileName, e1); grammar = new BufferedInputStream(resource); } try { InputSource isrc = new InputSource(grammar); isrc.setSystemId("jedit.jar"); parser.setContentHandler(xmh); parser.setDTDHandler(xmh); parser.setEntityResolver(xmh); parser.setErrorHandler(xmh); parser.parse(isrc); mode.setProperties(xmh.getModeProperties()); } catch (Throwable e) { error(fileName, e); } finally { IOUtilities.closeQuietly(grammar); } } //}}} //{{{ loadMode() method public void loadMode(Mode mode) { XModeHandler xmh = new XModeHandler(mode.getName()) { @Override public void error(String what, Object subst) { Log.log(Log.ERROR, this, subst); } @Override public TokenMarker getTokenMarker(String modeName) { Mode mode = getMode(modeName); if(mode == null) return null; else return mode.getTokenMarker(); } }; loadMode(mode, xmh); } //}}} //{{{ error() method protected void error(String file, Throwable e) { Log.log(Log.ERROR, this, e); } //}}} }