zeroheight / library-symbol-replacer

Sketch plugin to replace symbols in an existing documents with library symbols 💎 📚
MIT License
190 stars 6 forks source link

offer to merge local symbols that don't match names #1

Open RaphyRaph opened 7 years ago

RaphyRaph commented 7 years ago

The plugin works great for the case of cross document copy-pasted symbols, but it would be great to complete the symbol upgrading process by providing a list of the local symbols that don't name match and offer to replace all of their instances with existing library symbols.

robintindale commented 7 years ago

Thanks for FR 😄 What's the use-case for symbols that don't name-match? How were the libraries constructed? And picking a symbol-symbol mapping manually for all non-matching symbols sounds a bit cumbersome

RaphyRaph commented 7 years ago

The use case are:

I guess I'm simply asking for a way to select a local symbol and replace all its instances by another symbol (synced or not).

robintindale commented 7 years ago

Sounds like @sonburn's new plugin might be just what you need

https://www.facebook.com/groups/sketchformac/permalink/1941422106109938 https://github.com/sonburn/symbol-swapper

RaphyRaph commented 7 years ago

no, that one requires that the names match.

robintindale commented 7 years ago

Damn, true, sorry!

I don't have time to make a full plugin, but here's the code to replace a selected symbol with a symbol from a library. Change the LIB_NAME and SYMBOL_NAME as necessary.

You can run it by pressing Control+Shift+K, pasting it in, and pressing Run

var libraryName = 'LIB_NAME';
var symbolName = 'SYMBOL_NAME';

var localSymbol = context.selection.firstObject();
var controller = AppController.sharedInstance().librariesController();
var libraries = controller.userLibraries();
var library = null;
for (var i = 0; i < libraries.length; i++) {
  if (!libraries[i] || !libraries[i].document()) { continue; }
  if(String(libraries[i].name()) === String(libraryName)) {
    library = libraries[i];
    break;
  }
}

if(!library){
  log('Library not found');
  return;
}

var symbol = null;

var librarySymbols = library.document().documentData().localSymbols();
for(var i = 0 ; i < librarySymbols.length ; ++i){
  var librarySymbol = librarySymbols[i];
  var librarySymbolName = String(librarySymbol.name());
  if(librarySymbolName === String(symbolName)){
    symbol = librarySymbol;
  }
}

if(!symbol){
  log('Symbol not found in Library');
  return;
}

var documentData = context.document.documentData();
var importedSymbol = controller.importForeignSymbol_fromLibrary_intoDocument_(
  symbol, library, documentData);

var instances = localSymbol.allInstances();
for(var j = 0 ; j < instances.length ; ++j){
  instances[j].changeInstanceToSymbol(importedSymbol.symbolMaster());
}

var idmap = {};
var localId = String(localSymbol.symbolID());
idmap[localId] = String(importedSymbol.symbolMaster().symbolID());

var predicate = NSPredicate.predicateWithFormat("className == %@", "MSSymbolInstance");
var filteredArray = NSArray.array()
var loopPages = context.document.pages().objectEnumerator()
var page = null;
var scope = null;
while (page = loopPages.nextObject()) {
  scope = page.children();
  filteredArray = filteredArray.arrayByAddingObjectsFromArray(
    scope.filteredArrayUsingPredicate(predicate))
}

for(var i = 0 ; i < filteredArray.length ; ++i){
  MSLayerPaster.updateOverridesOnInstance_withIDMap_(filteredArray[i], idmap);
}

context.document.reloadInspector();

and here it is in action https://cl.ly/1D0C0R1v1e3X

RaphyRaph commented 7 years ago

THX!

sonburn commented 6 years ago

Just FYI, I added my own take on this functionality in Symbol Swapper v0.3 (https://github.com/sonburn/symbol-swapper) - Added ability to choose a symbol of a different name, and to only swap selected instance (not siblings).

RaphyRaph commented 6 years ago

@sonburn thx!