Package com.puppetlabs.geppetto.ui.editor

Source Code of com.puppetlabs.geppetto.ui.editor.MetadataModel$Replacement

/**
* Copyright (c) 2013 Puppet Labs, Inc. and other contributors, as listed below.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*   Puppet Labs
*/
package com.puppetlabs.geppetto.ui.editor;

import static com.puppetlabs.geppetto.common.Strings.emptyToNull;
import static com.puppetlabs.geppetto.common.Strings.trimToNull;
import static com.puppetlabs.geppetto.forge.Forge.FORGE;
import static com.puppetlabs.geppetto.forge.Forge.MODULEFILE_NAME;
import static com.puppetlabs.geppetto.forge.Forge.PARSE_FAILURE;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.ObjectMapper;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.Position;
import org.jrubyparser.CompatVersion;
import org.jrubyparser.Parser;
import org.jrubyparser.ast.RootNode;
import org.jrubyparser.lexer.SyntaxException;
import org.jrubyparser.parser.ParserConfiguration;

import com.google.common.io.CharStreams;
import com.puppetlabs.geppetto.diagnostic.Diagnostic;
import com.puppetlabs.geppetto.diagnostic.ExceptionDiagnostic;
import com.puppetlabs.geppetto.diagnostic.FileDiagnostic;
import com.puppetlabs.geppetto.forge.model.ModuleName;
import com.puppetlabs.geppetto.forge.model.ModuleName.BadNameCharactersException;
import com.puppetlabs.geppetto.forge.util.CallSymbol;
import com.puppetlabs.geppetto.forge.util.ModuleUtils;
import com.puppetlabs.geppetto.forge.util.RubyValueSerializer;
import com.puppetlabs.geppetto.forge.util.ValueSerializer;
import com.puppetlabs.geppetto.pp.dsl.ui.builder.PPModuleMetadataBuilder;
import com.puppetlabs.geppetto.semver.VersionRange;
import com.puppetlabs.geppetto.ui.UIPlugin;

public class MetadataModel {
  public interface Dependency {
    void delete();

    int getLine();

    String getModuleName();

    String getVersionRequirement();

    boolean isResolved();

    void setNameAndVersion(String moduleName, String versionRequirement);

    void setResolved(boolean flag);
  }

  class JsonDependency extends JsonObject implements Dependency {
    private boolean resolved;

    JsonDependency(ArgSticker depObj) {
      super(depObj);
    }

    @Override
    public void delete() {
      super.delete();
      removeFromArray(dependenciesCall);
    }

    public String getModuleName() {
      return getString(NAME);
    }

    public String getVersionRequirement() {
      return getString(VERSION_REQUIREMENT);
    }

    public boolean isResolved() {
      return resolved;
    }

    public void setNameAndVersion(String moduleName, String versionRequirement) {
      Map<String, Object> map = getMap();
      if(moduleName == null)
        map.remove(NAME);
      else
        map.put(NAME, moduleName);
      if(versionRequirement == null)
        map.remove(VERSION_REQUIREMENT);
      else
        map.put(VERSION_REQUIREMENT, versionRequirement);
      updateJson(4);
    }

    public void setResolved(boolean flag) {
      resolved = flag;
    }
  }

  abstract class JsonObject {
    private ArgSticker object;

    JsonObject(ArgSticker object) {
      this.object = object;
    }

    public void delete() {
      try {
        MetadataModel.this.remove(object);
      }
      catch(BadLocationException e) {
        throw new RuntimeException(e);
      }
    }

    public int getLine() {
      try {
        return document.getLineOfOffset(object.getOffset()) + 1;
      }
      catch(BadLocationException e) {
        return -1;
      }
    }

    @SuppressWarnings("unchecked")
    Map<String, Object> getMap() {
      Object value = object.getValue();
      if(value instanceof Map)
        return (Map<String, Object>) value;
      return Collections.emptyMap();
    }

    String getString(String key) {
      Object value = getMap().get(key);
      return value instanceof String
          ? (String) value
          : null;
    }

    void removeFromArray(CallSticker call) {
      ArgSticker[] args = call.getArguments();
      int idx = args.length;
      if(idx > 0) {
        int rdx = idx - 1;
        ArgSticker[] newArgs = new ArgSticker[rdx];
        if(rdx > 0) {
          while(--idx >= 0) {
            ArgSticker arg = args[idx];
            if(arg != object) {
              if(--rdx < 0)
                break;
              newArgs[rdx] = arg;
            }
          }
        }
        call.setArguments(newArgs);
      }
    }

    void updateJson(int indent) {
      MetadataModel.this.updateJson(object, indent);
    }
  }

  static class Replacement {
    int offset;

    int length;

    String prefix;

    String suffix;

    int getInjectLength(int totInjectLen) {
      return totInjectLen - (prefix.length() + suffix.length());
    }

    int getInjectOffset() {
      return offset + prefix.length();
    }
  }

  class RubyDependency implements Dependency {
    private CallSticker dependencyCall;

    private boolean resolved;

    RubyDependency(CallSticker dependency) {
      this.dependencyCall = dependency;
    }

    public void delete() {
      setArgValue(CallSymbol.dependency, dependencyCall);
    }

    public int getLine() {
      try {
        return document.getLineOfOffset(dependencyCall.getOffset()) + 1;
      }
      catch(BadLocationException e) {
        return -1;
      }
    }

    public String getModuleName() {
      return getArgValue(dependencyCall, 0);
    }

    public String getVersionRequirement() {
      return getArgValue(dependencyCall, 1);
    }

    public boolean isResolved() {
      return resolved;
    }

    public void setNameAndVersion(String moduleName, String versionRequirement) {
      dependencyCall = setArgValue(CallSymbol.dependency, dependencyCall, moduleName, versionRequirement);
    }

    public void setResolved(boolean flag) {
      resolved = flag;
    }
  }

  private static final String VERSION_REQUIREMENT = "version_requirement";

  private static final String NAME = "name";

  public static String getBadNameMessage(IllegalArgumentException e, boolean dependency) {
    String key;
    if(dependency)
      key = e instanceof BadNameCharactersException
          ? "_UI_Dependency_name_bad_characters"
          : "_UI_Dependency_name_bad_syntax";
    else
      key = e instanceof BadNameCharactersException
          ? "_UI_Module_name_bad_characters"
          : "_UI_Module_name_bad_syntax";
    return UIPlugin.getLocalString(key);
  }

  public static String getUnresolvedMessage(Dependency dep) {
    String vr = trimToNull(dep.getVersionRequirement());
    return vr == null
        ? UIPlugin.getLocalString("_UI_Unresolved_dependency_X", new Object[] { dep.getModuleName() })
        : UIPlugin.getLocalString(
          "_UI_Unresolved_dependency_X_Y", new Object[] { dep.getModuleName(), dep.getVersionRequirement() });

  }

  private Parser rubyParser;

  private ParserConfiguration rubyParserConfig;

  private CallSticker nameCall;

  private CallSticker versionCall;

  private CallSticker summaryCall;

  private CallSticker authorCall;

  private CallSticker descriptionCall;

  private CallSticker dependenciesCall;

  private CallSticker sourceCall;

  private CallSticker projectPageCall;

  private CallSticker licenseCall;

  private ValueSerializer serializer;

  private IDocument document;

  private final List<Dependency> dependencies = new ArrayList<Dependency>();

  private JsonFactory jsonFactory;

  private boolean syntaxError;

  private boolean dependencyErrors;

  synchronized void addCall(CallSymbol symbol, CallSticker call) {
    switch(symbol) {
      case author:
        authorCall = call;
        break;
      case dependencies:
        dependenciesCall = call;
        for(ArgSticker dep : call.getArguments())
          dependencies.add(new JsonDependency(dep));
        break;
      case dependency:
        dependencies.add(new RubyDependency(call));
        break;
      case description:
        descriptionCall = call;
        break;
      case license:
        licenseCall = call;
        break;
      case name:
        nameCall = call;
        break;
      case project_page:
        projectPageCall = call;
        break;
      case source:
        sourceCall = call;
        break;
      case summary:
        summaryCall = call;
        break;
      case version:
        versionCall = call;
    }
    addPositions(call);
  }

  public synchronized void addDependency(String moduleName, String versionRequirement) {
    ModuleName m;
    try {
      m = ModuleName.fromString(moduleName);
      moduleName = m.toString('/');
    }
    catch(IllegalArgumentException e) {
      m = null;
    }

    if(m != null) {
      for(Dependency dep : dependencies)
        try {
          ModuleName candidate = ModuleName.fromString(dep.getModuleName());
          if(m.equals(candidate)) {
            dep.setNameAndVersion(moduleName, versionRequirement);
            return;
          }
        }
        catch(IllegalArgumentException e) {

        }
    }
    Dependency dep;
    if(isRuby())
      dep = new RubyDependency(setArgValue(CallSymbol.dependency, null, moduleName, versionRequirement));
    else
      dep = createJsonDependency(moduleName, versionRequirement);

    dep.setResolved(isResolved(dep));
    dependencies.add(dep);
  }

  private void addPositions(CallSticker fragment) {
    try {
      document.addPosition(fragment);
      Position[] args = fragment.getArguments();
      for(int idx = 0; idx < args.length; ++idx)
        document.addPosition(args[idx]);
    }
    catch(BadLocationException e) {
      throw new RuntimeException(e);
    }
  }

  private Map<String, String> createDepsObj(String... values) {
    if(values.length == 0)
      return Collections.emptyMap();

    Map<String, String> value = new HashMap<String, String>();
    String name = emptyToNull(values[0]);
    if(name != null)
      value.put(NAME, name);

    if(values.length > 1) {
      String vr = emptyToNull(values[1]);
      if(vr != null)
        value.put(VERSION_REQUIREMENT, vr);
    }
    return value;
  }

  private JsonDependency createJsonDependency(String... values) {
    // Dependencies reside inside of the dependencies array. A new
    // dependency may potentially need to create this array from
    // scratch
    Map<String, String> depsObj = createDepsObj(values);
    StringBuilder bld = new StringBuilder();
    if(dependenciesCall == null || dependenciesCall.isDeleted) {
      Replacement r = prepareJSonInsert(-1, 2);
      bld.append(r.prefix);
      try {
        serializer.serialize(bld, "dependencies");
        bld.append(": [\n  ]");
        bld.append(r.suffix);
        document.replace(r.offset, r.length, bld.toString());
        dependenciesCall = new CallSticker(
          r.getInjectOffset(), r.getInjectLength(bld.length()), new ArgSticker[0]);
        document.addPosition(dependenciesCall);
      }
      catch(BadLocationException e) {
        throw new RuntimeException(e);
      }
      catch(IOException e) {
        throw new RuntimeException(e);
      }
      bld.setLength(0);
    }

    int last = dependenciesCall.getOffset() + dependenciesCall.getLength();
    String content = document.get();
    while(last >= 0 && content.charAt(last) != ']')
      --last;
    while(--last >= 0 && Character.isWhitespace(content.charAt(last)))
      ;
    ++last;

    ArgSticker arg = new ArgSticker(last, 0, depsObj);
    updateJson(arg, 4);
    ArgSticker[] args = dependenciesCall.getArguments();
    ArgSticker[] newArgs = new ArgSticker[args.length + 1];
    System.arraycopy(args, 0, newArgs, 0, args.length);
    newArgs[args.length] = arg;
    dependenciesCall.setArguments(args);
    return new JsonDependency(arg);
  }

  private CallSticker createNewCall(CallSymbol key, String... values) throws IOException, BadLocationException {
    if(!isRuby())
      return createNewJsonCall(key, values);

    String content = document.get();
    int insertPos = content.length();

    if(key == CallSymbol.dependency) {
      // This is a normal call but we make an effort to group the dependencies together
      // Find the last one
      CallSticker best = null;
      for(Dependency dep : dependencies) {
        CallSticker depSticker = ((RubyDependency) dep).dependencyCall;
        if(best == null || depSticker.getOffset() > best.getOffset())
          best = depSticker;
      }
      if(best != null) {
        // Insert directly after 'best' but on a new line
        insertPos = best.getOffset() + best.getLength();
        if(insertPos < content.length() && content.charAt(insertPos) == '\n')
          ++insertPos;
      }
    }

    StringBuilder bld = new StringBuilder();
    int nargs = values.length;

    ArgSticker[] argPositions = new ArgSticker[nargs];
    if(insertPos > 0 && content.charAt(insertPos - 1) != '\n')
      bld.append('\n');

    int callOffset = bld.length();
    bld.append(key.name());
    bld.append(' ');

    // Write empty strings for any arguments preceding the new one (in case
    // we get them in the wrong order)
    for(int idx = 0; idx < nargs; ++idx) {
      if(idx > 0)
        bld.append(", ");

      String value = values[idx];
      if(value == null)
        value = "";

      int argOffset = bld.length();
      serializer.serialize(bld, value);
      argPositions[idx] = new ArgSticker(insertPos + argOffset, bld.length() - argOffset, value);
    }
    bld.append('\n');
    document.replace(insertPos, 0, bld.toString());
    return new CallSticker(insertPos + callOffset, bld.length() - callOffset, argPositions);

  }

  private CallSticker createNewJsonCall(CallSymbol key, String... values) throws IOException, BadLocationException {
    Replacement r = prepareJSonInsert(-1, 2);

    StringBuilder bld = new StringBuilder();
    bld.append(r.prefix);
    serializer.serialize(bld, key.name());
    bld.append(": ");

    int nargs = values.length;
    ArgSticker[] argPositions = new ArgSticker[nargs];

    if(nargs > 1)
      bld.append('[');

    // Write empty strings for any arguments preceding the new one (in case
    // we get them in the wrong order)
    for(int idx = 0; idx < nargs; ++idx) {
      if(idx > 0)
        bld.append(", ");

      String value = values[idx];
      if(value == null)
        value = "";

      int argOffset = bld.length();
      serializer.serialize(bld, value);
      argPositions[idx] = new ArgSticker(r.offset + argOffset, bld.length() - argOffset, value);
    }
    if(nargs > 1)
      bld.append(']');

    bld.append(r.suffix);
    document.replace(r.offset, r.length, bld.toString());
    return new CallSticker(
      r.offset + r.prefix.length(), bld.length() - (r.prefix.length() + r.suffix.length()), argPositions);
  }

  private String getArgValue(CallSticker call, int argNo) {
    if(call != null && document != null && !call.isDeleted) {
      ArgSticker[] args = call.getArguments();
      if(argNo < args.length) {
        ArgSticker fragment = args[argNo];
        if(!fragment.isDeleted) {
          Object v = fragment.getValue();
          if(v != null)
            return v.toString();
        }
      }
    }
    return "";
  }

  public String getAuthor() {
    return getArgValue(authorCall, 0);
  }

  public synchronized Dependency[] getDependencies() {
    return dependencies.toArray(new Dependency[dependencies.size()]);
  }

  public synchronized int getDependencyIndex(Dependency dependency) {
    int idx = dependencies.size();
    while(--idx >= 0)
      if(dependencies.get(idx) == dependency)
        break;
    return idx;
  }

  public String getDescription() {
    return getArgValue(descriptionCall, 0);
  }

  IDocument getDocument() {
    return document;
  }

  public String getLicense() {
    return getArgValue(licenseCall, 0);
  }

  public String getModuleName() {
    return getArgValue(nameCall, 0);
  }

  public String getProjectPage() {
    return getArgValue(projectPageCall, 0);
  }

  public String getSource() {
    return getArgValue(sourceCall, 0);
  }

  public String getSummary() {
    return getArgValue(summaryCall, 0);
  }

  public String getVersion() {
    return getArgValue(versionCall, 0);
  }

  /**
   * Returns true if the model has unresolved dependencies
   */
  public boolean hasDependencyErrors() {
    return dependencyErrors;
  }

  private boolean isResolved(Dependency dep) {
    ModuleName name;
    VersionRange range;
    try {
      name = ModuleName.create(dep.getModuleName(), false);
      range = VersionRange.create(dep.getVersionRequirement());
      return PPModuleMetadataBuilder.getBestMatchingProject(name, range) != null;
    }
    catch(IllegalArgumentException e) {
      return false;
    }
  }

  private boolean isRuby() {
    return serializer == RubyValueSerializer.INSTANCE;
  }

  /**
   * Returns true if the parser was unable to parse the syntax of its given input
   */
  public boolean isSyntaxError() {
    return syntaxError;
  }

  private Replacement prepareJSonInsert(int insertPos, final int indent) {
    String content = document.get();

    // We should be inserting inside the top json object. It might not even exist at this point
    int start = content.indexOf('{');
    int end = content.lastIndexOf('}');

    if(insertPos == -1)
      insertPos = end >= 0
          ? end
          : content.length();

    StringBuilder bld = new StringBuilder();
    Replacement replacement = new Replacement();
    if(start >= 0) {
      if(end < start)
        replacement.suffix = "\n}";
    }
    else {
      bld.append("{\n");
      int idx = indent;
      while(--idx >= 0)
        bld.append(' ');
      replacement.prefix = bld.toString();
      if(end < 0)
        replacement.suffix = "\n}";
    }

    int replace = 0;

    if(replacement.prefix == null) {
      int idx = insertPos;
      boolean needsComma = true;
      while(--idx >= 0) {
        char c = content.charAt(idx);
        if(c == ',' || c == '[' || c == '{') {
          needsComma = false;
          break;
        }
        if(!Character.isWhitespace(c))
          break;
        ++replace;
      }
      replacement.offset = ++idx;
      if(needsComma)
        bld.append(',');
      bld.append('\n');
      idx = indent;
      while(--idx >= 0)
        bld.append(' ');
      replacement.prefix = bld.toString();
    }
    else
      replacement.offset = insertPos;

    if(replacement.suffix == null) {
      boolean needsComma = true;
      int idx = insertPos;
      int top = content.length();
      while(idx < top) {
        char c = content.charAt(idx);
        if(c == ',' || c == ']' || c == '}') {
          needsComma = false;
          break;
        }
        if(!Character.isWhitespace(c))
          break;
        ++replace;
        ++idx;
      }
      bld.setLength(0);
      idx = indent;
      if(needsComma)
        bld.append(',');
      else
        // We are followed by ']' or '}'
        idx -= 2;

      bld.append('\n');
      while(--idx >= 0)
        bld.append(' ');
      replacement.suffix = bld.toString();
    }
    replacement.length = replace;
    return replacement;
  }

  private void remove(int offset, int len) throws BadLocationException {
    String content = document.get();
    int last = content.length();
    if(offset > last)
      return;

    // Find preceding position that isn't whitespace.
    boolean removesPreceedingComma = false;
    boolean atZero = offset == 0;
    if(!atZero) {
      char c = 0;
      while(offset > 0) {
        --offset;
        ++len;
        c = content.charAt(offset);
        if(!Character.isWhitespace(c))
          break;
      }
      removesPreceedingComma = c == ',';
    }

    if(!removesPreceedingComma) {
      if(!atZero) {
        ++offset; // Retain this character
        --len;
      }

      // Find out if we need to remove a succeeding comma instead
      int pos = offset + len;
      int step = 0;
      while(pos < last) {
        ++step;
        char c = content.charAt(pos);
        if(c == ',') {
          len += step;
          break;
        }
        if(!Character.isWhitespace(c))
          break;
        ++pos;
      }
    }
    document.replace(offset, len, "");
  }

  private void remove(Position pos) throws BadLocationException {
    document.removePosition(pos);
    remove(pos.getOffset(), pos.getLength());
  }

  public synchronized void removeDependency(Dependency dep) {
    if(dependencies.remove(dep))
      dep.delete();
  }

  private CallSticker setArgValue(CallSymbol key, CallSticker call, String... values) {
    try {
      if(call == null || call.isDeleted)
        // We need to append a new call to the document
        return createNewCall(key, values);

      ArgSticker[] argPositions = call.getArguments();
      boolean hasArgs = false;
      boolean hasChanges = false;
      int idx = values.length;
      while(--idx >= 0) {
        String arg = values[idx];
        Object oldArg = null;
        if(idx < argPositions.length)
          oldArg = argPositions[idx].getValue();

        if(arg != null) {
          hasArgs = true;
          if(!hasChanges)
            hasChanges = !arg.equals(oldArg);
        }
        else if(oldArg != null)
          hasChanges = true;
      }

      if(!hasArgs) {
        remove(call);
        return null;
      }

      if(!hasChanges)
        return call;

      boolean ruby = isRuby();

      if(!ruby && key == CallSymbol.dependency)
        // Needs special handling since it's stored as json objects
        // in an array
        return updateJsonDependency(call, values);

      // Replace or add arguments to existing call
      ArgSticker[] newPositions = null;
      int nargs = values.length;
      if(nargs > argPositions.length) {
        // Call has additional parameters
        newPositions = new ArgSticker[nargs];
        for(idx = 0; idx < argPositions.length; ++idx)
          newPositions[idx] = argPositions[idx];
      }

      int newArgsLen = 0;
      for(idx = 0; idx < nargs; ++idx) {
        String value = values[idx];
        if(idx < argPositions.length) {
          // Replace argument content
          ArgSticker pos = argPositions[idx];
          pos.setValue(value);
          if(value == null)
            value = ruby
                ? "''"
                : "\"\"";
          else {
            StringBuilder bld = new StringBuilder();
            serializer.serialize(bld, value);
            value = bld.toString();
          }
          document.replace(pos.getOffset(), pos.getLength(), value);
          pos.length = value.length();
        }
        else {
          int callEnd = call.getOffset() + call.getLength();
          String content = document.get();
          if(callEnd >= content.length())
            callEnd = content.length() - 1;

          // Find last non-whitespace character
          while(callEnd >= 0 && Character.isWhitespace(content.charAt(callEnd)))
            --callEnd;
          ++callEnd; // Directly after last non-whitespace

          StringBuilder bld = new StringBuilder();
          if(idx > 0)
            bld.append(',');
          bld.append(' ');
          int argStart = bld.length();
          serializer.serialize(bld, value);
          newPositions[idx] = new ArgSticker(callEnd + argStart, bld.length() - argStart, value);
          document.replace(callEnd, 0, bld.toString());
          newArgsLen += bld.length();
        }
      }
      if(newPositions != null)
        call = new CallSticker(call.offset, call.length + newArgsLen, newPositions);
      return call;
    }
    catch(BadLocationException e) {
      throw new RuntimeException(e);
    }
    catch(IOException e) {
      throw new RuntimeException(e);
    }
  }

  public void setAuthor(String author) {
    authorCall = setArgValue(CallSymbol.author, authorCall, author);
  }

  public void setDescription(String description) {
    descriptionCall = setArgValue(CallSymbol.description, descriptionCall, description);
  }

  synchronized void setDocument(IDocument document, IPath path, Diagnostic chain) {
    syntaxError = false;
    dependencyErrors = false;
    authorCall = null;
    descriptionCall = null;
    licenseCall = null;
    nameCall = null;
    projectPageCall = null;
    sourceCall = null;
    summaryCall = null;
    versionCall = null;
    dependencies.clear();
    this.document = document;
    if(document != null) {
      try {
        if(MODULEFILE_NAME.equals(path.lastSegment())) {
          if(rubyParser == null) {
            serializer = RubyValueSerializer.INSTANCE;
            rubyParser = new Parser();
            rubyParserConfig = new ParserConfiguration(0, CompatVersion.RUBY1_9);
          }
          RootNode root = (RootNode) rubyParser.parse(
            path.toOSString(), new StringReader(document.get()), rubyParserConfig);
          new LenientModulefileParser(this).parseRubyAST(root, chain);
        }
        else {
          if(jsonFactory == null) {
            jsonFactory = new JsonFactory();
            serializer = new ValueSerializer() {
              @Override
              public void serialize(Appendable bld, Object value) throws IOException {
                JsonGenerator generator = jsonFactory.createJsonGenerator(CharStreams.asWriter(bld));
                generator.setCodec(new ObjectMapper(jsonFactory));
                generator.writeObject(value);
                generator.flush();
              }
            };
          }
          new LenientMetadataJsonParser(this).parse(path.toFile(), document.get(), chain);
        }
        for(Dependency dep : dependencies) {
          boolean resolved = isResolved(dep);
          if(!resolved) {
            FileDiagnostic diag = new FileDiagnostic(
              Diagnostic.ERROR, FORGE, getUnresolvedMessage(dep), path.toFile());
            diag.setLineNumber(dep.getLine());
            chain.addChild(diag);
            dependencyErrors = true;
          }
          dep.setResolved(resolved);
        }
      }
      catch(SyntaxException e) {
        syntaxError = true;
        chain.addChild(ModuleUtils.createSyntaxErrorDiagnostic(e, null));
      }
      catch(Exception e) {
        syntaxError = true;
        e.printStackTrace();
        chain.addChild(new ExceptionDiagnostic(
          Diagnostic.ERROR, PARSE_FAILURE, "Unable to parse file " + path, e));
      }
    }
  }

  public void setLicense(String license) {
    licenseCall = setArgValue(CallSymbol.license, licenseCall, license);
  }

  public void setModuleName(String moduleName) {
    nameCall = setArgValue(CallSymbol.name, nameCall, moduleName);
  }

  public void setProjectPage(String projectPage) {
    projectPageCall = setArgValue(CallSymbol.project_page, projectPageCall, projectPage);
  }

  public void setSource(String source) {
    sourceCall = setArgValue(CallSymbol.source, sourceCall, source);
  }

  public void setSummary(String summary) {
    summaryCall = setArgValue(CallSymbol.summary, summaryCall, summary);
  }

  public void setVersion(String version) {
    versionCall = setArgValue(CallSymbol.version, versionCall, version);
  }

  private void updateJson(ArgSticker arg, int indent) {
    if(arg == null || arg.isDeleted)
      return;

    try {
      Replacement r = prepareJSonInsert(arg.getOffset(), indent);

      StringBuilder bld = new StringBuilder();
      bld.append(r.prefix);
      serializer.serialize(bld, arg.getValue());
      bld.append(r.suffix);

      document.replace(r.offset, r.length, bld.toString());
      arg.setOffset(r.getInjectOffset());
      arg.setLength(r.getInjectLength(bld.length()));
    }
    catch(BadLocationException e) {
      throw new RuntimeException(e);
    }
    catch(IOException e) {
      throw new RuntimeException(e);
    }
  }

  private CallSticker updateJsonDependency(CallSticker call, String... values) {
    ArgSticker sticker = new ArgSticker(call.getOffset(), call.getLength(), createDepsObj(values));
    updateJson(sticker, 4);
    call.setOffset(sticker.getOffset());
    call.setLength(sticker.getLength());
    return call;
  }
}
TOP

Related Classes of com.puppetlabs.geppetto.ui.editor.MetadataModel$Replacement

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.