// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.debug.core.model;
import java.util.List;
/**
* Supports better matching of local source files with remote scripts by leveraging the fact
* that the original source could be preprocessed by adding a prefix and suffix (usually to
* put user code in some scope). This class tries to match script source with a list of
* known wrappers.
*/
public class SourceWrapSupport {
private final List<Wrapper> wrappers;
public SourceWrapSupport(List<Wrapper> wrappers) {
this.wrappers = wrappers;
}
/**
* Describes a known type of script source wrapper. The wrapping is essentially adding
* a prefix and suffix, but these parts can be flexible.
* This object is responsible for recognizing a particular wrapping.
*/
public interface Wrapper {
/**
* @return user-visible wrapper name
*/
String getName();
/**
* Checks whether remoteContext text has this particular wrapping.
* @return match object if input matches or null
*/
Match match(String remoteContent);
/**
* Defines a particular wrapper match. It can be used to construct identical wrapping
* for user-edited script source. The separate interface is needed because its instance
* can hold parameters of this particular prefix/suffix, if they can match multiple strings
* (for example RegExp-based).
*/
interface Match {
Wrapper getWrapper();
/**
* Wraps a user source identically to how the original script was wrapped.
*/
String wrap(String localContent);
/**
* @return the prefix length (used for position recalculation in diff)
*/
int getPrefixLength();
/**
* @return the suffix length (used for position recalculation in diff)
*/
int getSuffixLength();
}
}
/**
* Matches the remote script source against all known wrappers.
* @return match object of first matching wrapper or null if no wrapper match
*/
public Wrapper.Match chooseWrapper(String remoteContent) {
for (Wrapper nextWrapper : wrappers) {
Wrapper.Match match = nextWrapper.match(remoteContent);
if (match != null) {
return match;
}
}
return null;
}
// Simple prefix-suffix-based. More complex implementations are expected.
public static class StringBasedWrapper implements Wrapper {
private final String name;
private final String prefix;
private final String suffix;
public StringBasedWrapper(String name, String prefix, String suffix) {
this.name = name;
this.prefix = prefix;
this.suffix = suffix;
}
@Override public String getName() {
return name;
}
@Override
public Match match(String remoteContent) {
if (remoteContent.length() < prefix.length() + suffix.length()) {
return null;
}
if (!remoteContent.startsWith(prefix) || !remoteContent.endsWith(suffix)) {
return null;
}
return singleMatch;
}
private final Match singleMatch = new Match() {
@Override public Wrapper getWrapper() {
return StringBasedWrapper.this;
}
@Override public String wrap(String localContent) {
return prefix + localContent + suffix;
}
@Override public int getPrefixLength() {
return prefix.length();
}
@Override public int getSuffixLength() {
return suffix.length();
}
};
}
}